Revision: 2708 Author: piumarta Date: 2013-03-22 07:11:57 -0700 (Fri, 22 Mar 2013) Log Message: ----------- update to most recent available sources Modified Paths: -------------- trunk/platforms/win32/plugins/SqueakSSL/sqWin32SSL.c Modified: trunk/platforms/win32/plugins/SqueakSSL/sqWin32SSL.c =================================================================== --- trunk/platforms/win32/plugins/SqueakSSL/sqWin32SSL.c 2013-03-22 12:38:54 UTC (rev 2707) +++ trunk/platforms/win32/plugins/SqueakSSL/sqWin32SSL.c 2013-03-22 14:11:57 UTC (rev 2708) @@ -115,11 +115,15 @@ } /* Set up the local certificate for SSL */ +#define MAX_NAME_SIZE 4096 static sqInt sqSetupCert(sqSSL *ssl, char *certName, int server) { SCHANNEL_CRED sc_cred = { 0 }; SECURITY_STATUS ret; HCERTSTORE hStore; PCCERT_CONTEXT pContext = NULL; + DWORD dwPropSize; + WCHAR wFriendlyName[MAX_NAME_SIZE]; + char bFriendlyName[MAX_NAME_SIZE]; if(certName) { hStore = CertOpenSystemStore(0, "MY"); @@ -127,12 +131,32 @@ if(ssl->loglevel) printf("sqSetupCert: CertOpenSystemStore failed\n"); return 0; } - pContext = CertFindCertificateInStore(hStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, - 0, CERT_FIND_SUBJECT_STR_A, certName, NULL); + pContext = NULL; - /* XXXX: Fail? Or just not provide the cert? For now, fail. */ + /* Enumerate the certificate store to find the cert with the given friendly name */ + while(pContext = CertEnumCertificatesInStore(hStore, pContext)) { + if(ssl->loglevel) printf("Checking certificate: "); + dwPropSize = MAX_NAME_SIZE * sizeof(WCHAR); + if(!CertGetCertificateContextProperty(pContext, CERT_FRIENDLY_NAME_PROP_ID, wFriendlyName, &dwPropSize)) { + if(ssl->loglevel) printf("<no friendly name>"); + continue; + } + if(!WideCharToMultiByte(CP_UTF8, 0, wFriendlyName, -1, bFriendlyName, MAX_NAME_SIZE, NULL, NULL)) { + if(ssl->loglevel) printf("<utf-8 conversion failure>"); + continue; + } + if(ssl->loglevel) printf("%s\n", bFriendlyName); + if(strcmp(certName, bFriendlyName) == 0) break; + } + + if(pContext == 0) { + /* For compatibility with older versions of SqueakSSL, attempt to match against subject string */ + pContext = CertFindCertificateInStore(hStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + 0, CERT_FIND_SUBJECT_STR_A, certName, NULL); + } + if(!pContext) { - if(ssl->loglevel) printf("sqSetupCert: CertFindCertitficateInStore failed\n"); + if(ssl->loglevel) printf("sqSetupCert: No suitable certificate found\n"); CertCloseStore(hStore, 0); return 0; } @@ -471,6 +495,9 @@ int count; /* Handle various failure conditions */ switch(ret) { + case SEC_E_INCOMPLETE_MESSAGE: + /* not enough data for the handshake to complete */ + return SQSSL_NEED_MORE_DATA; case SEC_I_CONTINUE_NEEDED: /* Send contents back to peer and come back with more data */ count = sqCopyDescToken(ssl, ssl->sbdOut, dstBuf, dstLen); @@ -500,7 +527,15 @@ /* TODO: Look at retFlags */ ssl->state = SQSSL_CONNECTED; - sqCopyExtraData(ssl, ssl->sbdOut); + /* If there is SECBUFFER_EXTRA in the input we need to retain it */ + if(ssl->inbuf[1].BufferType == SECBUFFER_EXTRA) { + int extra = ssl->inbuf[1].cbBuffer; + if(ssl->loglevel) printf("sqConnectSSL: Retaining %d token bytes\n", extra); + memmove(ssl->dataBuf, ssl->dataBuf + (ssl->dataLen - extra), extra); + ssl->dataLen = extra; + } else { + sqCopyExtraData(ssl, ssl->sbdOut); + } ret = QueryContextAttributes(&ssl->sslCtxt, SECPKG_ATTR_STREAM_SIZES, &ssl->sslSizes); if(ssl->loglevel) printf("sqConnectSSL: Maximum message size is %d bytes\n", ssl->sslSizes.cbMaximumMessage); @@ -576,6 +611,9 @@ if(ret != SEC_E_OK) { /* Handle various failure conditions */ switch(ret) { + case SEC_E_INCOMPLETE_MESSAGE: + /* not enough data for the handshake to complete */ + return SQSSL_NEED_MORE_DATA; case SEC_I_CONTINUE_NEEDED: /* Send contents back to peer and come back with more data */ return sqCopyDescToken(ssl, ssl->sbdOut, dstBuf, dstLen); @@ -677,6 +715,11 @@ if(ssl == NULL || ssl->state != SQSSL_CONNECTED) return SQSSL_INVALID_STATE; + /* Workaround for a strange Windows issue: Directly after an SSL handshake + has completed, calling DecryptMessage() with empty input can fail with + SEC_E_INVALID_TOKEN for no apparent reason. */ + if(!ssl->dataLen && !srcLen) return 0; + if(ssl->dataLen + srcLen > ssl->dataMax) { /* resize the read buffer */ ssl->dataMax += (srcLen < 4096) ? (4096) : (srcLen+1024); @@ -708,6 +751,12 @@ ssl->sbdIn.cBuffers = 4; ret = DecryptMessage(&ssl->sslCtxt, &ssl->sbdIn, 0, 0); + if(ret == SEC_I_CONTEXT_EXPIRED) { + /* The remote has shut down the ssl session */ + ssl->dataLen = 0; + return 0; + } + /* Copy the result into destination buffer */ total = 0; for(i=0;i<4;i++) { @@ -757,6 +806,48 @@ return NULL; } +/* sqAddPfxCertToStore: Adds a PFX certificate to MY certificate store. + Arguments: + pfxData - the contents of the PFX certificate file + pfxLen - the length of the PFX certificate file + passData - the utf8 encoded password for the file + passLen - the size of the password + Returns: 1 on success, 0 on failure +*/ +static sqInt sqAddPfxCertToStore(char *pfxData, sqInt pfxLen, char *passData, sqInt passLen) { + PCCERT_CONTEXT pContext; + HCERTSTORE pfxStore, myStore; + CRYPT_DATA_BLOB blob; + WCHAR widePass[4096]; + + /* Verify that this is a PFX file */ + blob.cbData = pfxLen; + blob.pbData = pfxData; + if(!PFXIsPFXBlob(&blob)) return 0; /* Not a PFX blob */ + + /* Verify that the password is all right */ + widePass[0] = 0; + if(passLen > 0) { + DWORD wideLen = MultiByteToWideChar(CP_UTF8, 0, passData, passLen, widePass, 4095); + widePass[wideLen] = 0; + } + if(!PFXVerifyPassword(&blob, widePass, 0)) return 0; /* Invalid password */ + + /* Import the PFX blob into a temporary store */ + pfxStore = PFXImportCertStore(&blob, widePass, 0); + if(!pfxStore) return 0; + + /* And copy the certificates to MY store */ + myStore = CertOpenSystemStore(0, "MY"); + pContext = NULL; + while(pContext = CertEnumCertificatesInStore(pfxStore, pContext)) { + CertAddCertificateContextToStore(myStore, pContext, CERT_STORE_ADD_REPLACE_EXISTING, NULL); + } + CertCloseStore(myStore, 0); + CertCloseStore(pfxStore, 0); + return 1; +} + /* sqSetStringPropertySSL: Set a string property in SSL. Arguments: handle - the ssl handle @@ -780,6 +871,9 @@ switch(propID) { case SQSSL_PROP_CERTNAME: ssl->certName = property; break; + /* Platform specific: Adds a .PFX file to MY certificate store w/o password. + Useful for installing the default test certificate in SqueakSSL. */ + case 10001: return sqAddPfxCertToStore(propName, propLen, NULL, 0); default: if(ssl->loglevel) printf("sqSetStringPropertySSL: Unknown property ID %d\n", propID); return 0; |
Free forum by Nabble | Edit this page |