Skip to content

Commit f439a4c

Browse files
Andreas RaabAndreas Raab
authored andcommitted
- Update SqueakSSL code to use the friendly name of the cert which is editable in MMC and allows for disambiguation of certs
- Provide the ability to install a .pfx for unit testing
1 parent a940f9e commit f439a4c

File tree

1 file changed

+76
-4
lines changed

1 file changed

+76
-4
lines changed

src/Win32/sqWin32SSL.c

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,24 +115,48 @@ static sqInt sqCopyDescToken(sqSSL *ssl, SecBufferDesc sbd, char *dstBuf, sqInt
115115
}
116116

117117
/* Set up the local certificate for SSL */
118+
#define MAX_NAME_SIZE 4096
118119
static sqInt sqSetupCert(sqSSL *ssl, char *certName, int server) {
119120
SCHANNEL_CRED sc_cred = { 0 };
120121
SECURITY_STATUS ret;
121122
HCERTSTORE hStore;
122123
PCCERT_CONTEXT pContext = NULL;
124+
DWORD dwPropSize;
125+
WCHAR wFriendlyName[MAX_NAME_SIZE];
126+
char bFriendlyName[MAX_NAME_SIZE];
123127

124128
if(certName) {
125129
hStore = CertOpenSystemStore(0, "MY");
126130
if(!hStore) {
127131
if(ssl->loglevel) printf("sqSetupCert: CertOpenSystemStore failed\n");
128132
return 0;
129133
}
130-
pContext = CertFindCertificateInStore(hStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
131-
0, CERT_FIND_SUBJECT_STR_A, certName, NULL);
134+
pContext = NULL;
135+
136+
/* Enumerate the certificate store to find the cert with the given friendly name */
137+
while(pContext = CertEnumCertificatesInStore(hStore, pContext)) {
138+
if(ssl->loglevel) printf("Checking certificate: ");
139+
dwPropSize = MAX_NAME_SIZE * sizeof(WCHAR);
140+
if(!CertGetCertificateContextProperty(pContext, CERT_FRIENDLY_NAME_PROP_ID, wFriendlyName, &dwPropSize)) {
141+
if(ssl->loglevel) printf("<no friendly name>");
142+
continue;
143+
}
144+
if(!WideCharToMultiByte(CP_UTF8, 0, wFriendlyName, -1, bFriendlyName, MAX_NAME_SIZE, NULL, NULL)) {
145+
if(ssl->loglevel) printf("<utf-8 conversion failure>");
146+
continue;
147+
}
148+
if(ssl->loglevel) printf("%s\n", bFriendlyName);
149+
if(strcmp(certName, bFriendlyName) == 0) break;
150+
}
151+
152+
if(pContext == 0) {
153+
/* For compatibility with older versions of SqueakSSL, attempt to match against subject string */
154+
pContext = CertFindCertificateInStore(hStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
155+
0, CERT_FIND_SUBJECT_STR_A, certName, NULL);
156+
}
132157

133-
/* XXXX: Fail? Or just not provide the cert? For now, fail. */
134158
if(!pContext) {
135-
if(ssl->loglevel) printf("sqSetupCert: CertFindCertitficateInStore failed\n");
159+
if(ssl->loglevel) printf("sqSetupCert: No suitable certificate found\n");
136160
CertCloseStore(hStore, 0);
137161
return 0;
138162
}
@@ -587,6 +611,9 @@ sqInt sqAcceptSSL(sqInt handle, char* srcBuf, sqInt srcLen, char *dstBuf, sqInt
587611
if(ret != SEC_E_OK) {
588612
/* Handle various failure conditions */
589613
switch(ret) {
614+
case SEC_E_INCOMPLETE_MESSAGE:
615+
/* not enough data for the handshake to complete */
616+
return SQSSL_NEED_MORE_DATA;
590617
case SEC_I_CONTINUE_NEEDED:
591618
/* Send contents back to peer and come back with more data */
592619
return sqCopyDescToken(ssl, ssl->sbdOut, dstBuf, dstLen);
@@ -779,6 +806,48 @@ char* sqGetStringPropertySSL(sqInt handle, int propID) {
779806
return NULL;
780807
}
781808

809+
/* sqAddPfxCertToStore: Adds a PFX certificate to MY certificate store.
810+
Arguments:
811+
pfxData - the contents of the PFX certificate file
812+
pfxLen - the length of the PFX certificate file
813+
passData - the utf8 encoded password for the file
814+
passLen - the size of the password
815+
Returns: 1 on success, 0 on failure
816+
*/
817+
static sqInt sqAddPfxCertToStore(char *pfxData, sqInt pfxLen, char *passData, sqInt passLen) {
818+
PCCERT_CONTEXT pContext;
819+
HCERTSTORE pfxStore, myStore;
820+
CRYPT_DATA_BLOB blob;
821+
WCHAR widePass[4096];
822+
823+
/* Verify that this is a PFX file */
824+
blob.cbData = pfxLen;
825+
blob.pbData = pfxData;
826+
if(!PFXIsPFXBlob(&blob)) return 0; /* Not a PFX blob */
827+
828+
/* Verify that the password is all right */
829+
widePass[0] = 0;
830+
if(passLen > 0) {
831+
DWORD wideLen = MultiByteToWideChar(CP_UTF8, 0, passData, passLen, widePass, 4095);
832+
widePass[wideLen] = 0;
833+
}
834+
if(!PFXVerifyPassword(&blob, widePass, 0)) return 0; /* Invalid password */
835+
836+
/* Import the PFX blob into a temporary store */
837+
pfxStore = PFXImportCertStore(&blob, widePass, 0);
838+
if(!pfxStore) return 0;
839+
840+
/* And copy the certificates to MY store */
841+
myStore = CertOpenSystemStore(0, "MY");
842+
pContext = NULL;
843+
while(pContext = CertEnumCertificatesInStore(pfxStore, pContext)) {
844+
CertAddCertificateContextToStore(myStore, pContext, CERT_STORE_ADD_REPLACE_EXISTING, NULL);
845+
}
846+
CertCloseStore(myStore, 0);
847+
CertCloseStore(pfxStore, 0);
848+
return 1;
849+
}
850+
782851
/* sqSetStringPropertySSL: Set a string property in SSL.
783852
Arguments:
784853
handle - the ssl handle
@@ -802,6 +871,9 @@ sqInt sqSetStringPropertySSL(sqInt handle, int propID, char *propName, sqInt pro
802871

803872
switch(propID) {
804873
case SQSSL_PROP_CERTNAME: ssl->certName = property; break;
874+
/* Platform specific: Adds a .PFX file to MY certificate store w/o password.
875+
Useful for installing the default test certificate in SqueakSSL. */
876+
case 10001: return sqAddPfxCertToStore(propName, propLen, NULL, 0);
805877
default:
806878
if(ssl->loglevel) printf("sqSetStringPropertySSL: Unknown property ID %d\n", propID);
807879
return 0;

0 commit comments

Comments
 (0)