OSStatus CertParser::initWithSecCert( SecCertificateRef secCert) { OSStatus ortn; CSSM_DATA certData; assert(mClHand == 0); ortn = SecCertificateGetCLHandle(secCert, &mClHand); if(ortn) { return ortn; } ortn = SecCertificateGetData(secCert, &certData); if(ortn) { return ortn; } return (OSStatus)initWithData(certData); }
OSStatus parseIncomingCerts( SSLContext *ctx, CFArrayRef certs, SSLCertificate **destCert, /* &ctx->{localCert,encryptCert} */ CSSM_KEY_PTR *pubKey, /* &ctx->signingPubKey, etc. */ SecKeyRef *privKeyRef, /* &ctx->signingPrivKeyRef, etc. */ CSSM_ALGORITHMS *signerAlg) /* optional */ { CFIndex numCerts; CFIndex cert; SSLCertificate *certChain = NULL; SSLCertificate *thisSslCert; OSStatus ortn; SecIdentityRef identity; SecCertificateRef certRef; SecKeyRef keyRef; CSSM_DATA certData; CSSM_CL_HANDLE clHand; // carefully derive from a SecCertificateRef CSSM_RETURN crtn; CSSM_KEY_PTR *pubKey; SecKeyRef *privKeyRef; assert(ctx != NULL); assert(destCert != NULL); /* though its referent may be NULL */ assert(sslPubKey != NULL); assert(sslPrivKeyRef != NULL); pubKey = &sslPubKey->key; privKeyRef = &sslPrivKey->key; sslDeleteCertificateChain(*destCert, ctx); *destCert = NULL; *pubKey = NULL; *privKeyRef = NULL; if(certs == NULL) { sslErrorLog("parseIncomingCerts: NULL incoming cert array\n"); return errSSLBadCert; } numCerts = CFArrayGetCount(certs); if(numCerts == 0) { sslErrorLog("parseIncomingCerts: empty incoming cert array\n"); return errSSLBadCert; } /* * Certs[0] is an SecIdentityRef from which we extract subject cert, * privKeyRef, pubKey. * * 1. ensure the first element is a SecIdentityRef. */ identity = (SecIdentityRef)CFArrayGetValueAtIndex(certs, 0); if(identity == NULL) { sslErrorLog("parseIncomingCerts: bad cert array (1)\n"); return paramErr; } if(CFGetTypeID(identity) != SecIdentityGetTypeID()) { sslErrorLog("parseIncomingCerts: bad cert array (2)\n"); return paramErr; } /* * 2. Extract cert, keys and convert to local format. */ ortn = SecIdentityCopyCertificate(identity, &certRef); if(ortn) { sslErrorLog("parseIncomingCerts: bad cert array (3)\n"); return ortn; } ortn = secCertToSslCert(ctx, certRef, &thisSslCert); if(ortn) { sslErrorLog("parseIncomingCerts: bad cert array (4)\n"); return ortn; } /* enqueue onto head of cert chain */ thisSslCert->next = certChain; certChain = thisSslCert; if(signerAlg != NULL) { ortn = sslCertSignerAlg(certRef, signerAlg); if(ortn) { return ortn; } } /* fetch private key from identity */ ortn = SecIdentityCopyPrivateKey(identity, &keyRef); if(ortn) { sslErrorLog("parseIncomingCerts: SecIdentityCopyPrivateKey err %d\n", (int)ortn); return ortn; } *privKeyRef = keyRef; /* obtain public key from cert */ ortn = SecCertificateGetCLHandle(certRef, &clHand); if(ortn) { sslErrorLog("parseIncomingCerts: SecCertificateGetCLHandle err %d\n", (int)ortn); return ortn; } certData.Data = thisSslCert->derCert.data; certData.Length = thisSslCert->derCert.length; crtn = CSSM_CL_CertGetKeyInfo(clHand, &certData, pubKey); if(crtn) { sslErrorLog("parseIncomingCerts: CSSM_CL_CertGetKeyInfo err\n"); return (OSStatus)crtn; } /* OK, that's the subject cert. Fetch optional remaining certs. */ /* * Convert: CFArray of SecCertificateRefs --> chain of SSLCertificates. * Incoming certs have root last; SSLCertificate chain has root * first. */ for(cert=1; cert<numCerts; cert++) { certRef = (SecCertificateRef)CFArrayGetValueAtIndex(certs, cert); if(certRef == NULL) { sslErrorLog("parseIncomingCerts: bad cert array (5)\n"); return paramErr; } if(CFGetTypeID(certRef) != SecCertificateGetTypeID()) { sslErrorLog("parseIncomingCerts: bad cert array (6)\n"); return paramErr; } /* Extract cert, convert to local format. */ ortn = secCertToSslCert(ctx, certRef, &thisSslCert); if(ortn) { sslErrorLog("parseIncomingCerts: bad cert array (7)\n"); return ortn; } /* enqueue onto head of cert chain */ thisSslCert->next = certChain; certChain = thisSslCert; } /* SUCCESS */ *destCert = certChain; return noErr; /* free certChain, everything in it, other vars, return ortn */ sslDeleteCertificateChain(certChain, ctx); /* FIXME - anything else? */ return ortn; }
// Extract the issuer and serial number from a certificate SecCmsIssuerAndSN *CERT_GetCertIssuerAndSN(PRArenaPool *pl, SecCertificateRef cert) { OSStatus status; SecCmsIssuerAndSN *certIssuerAndSN; CSSM_CL_HANDLE clHandle; CSSM_DATA_PTR serialNumber = 0; CSSM_DATA_PTR issuer = 0; CSSM_DATA certData = {}; CSSM_HANDLE resultsHandle = 0; uint32 numberOfFields = 0; CSSM_RETURN result; void *mark; mark = PORT_ArenaMark(pl); status = SecCertificateGetCLHandle(cert, &clHandle); if (status) goto loser; status = SecCertificateGetData(cert, &certData); if (status) goto loser; /* Get the issuer from the cert. */ result = CSSM_CL_CertGetFirstFieldValue(clHandle, &certData, &OID_X509V1IssuerNameStd, &resultsHandle, &numberOfFields, &issuer); if (result || numberOfFields < 1) goto loser; result = CSSM_CL_CertAbortQuery(clHandle, resultsHandle); if (result) goto loser; /* Get the serialNumber from the cert. */ result = CSSM_CL_CertGetFirstFieldValue(clHandle, &certData, &CSSMOID_X509V1SerialNumber, &resultsHandle, &numberOfFields, &serialNumber); if (result || numberOfFields < 1) goto loser; result = CSSM_CL_CertAbortQuery(clHandle, resultsHandle); if (result) goto loser; /* Allocate the SecCmsIssuerAndSN struct. */ certIssuerAndSN = (SecCmsIssuerAndSN *)PORT_ArenaZAlloc (pl, sizeof(SecCmsIssuerAndSN)); if (certIssuerAndSN == NULL) goto loser; /* Copy the issuer. */ certIssuerAndSN->derIssuer.Data = (uint8 *) PORT_ArenaAlloc(pl, issuer->Length); if (!certIssuerAndSN->derIssuer.Data) goto loser; PORT_Memcpy(certIssuerAndSN->derIssuer.Data, issuer->Data, issuer->Length); certIssuerAndSN->derIssuer.Length = issuer->Length; /* Copy the serialNumber. */ certIssuerAndSN->serialNumber.Data = (uint8 *) PORT_ArenaAlloc(pl, serialNumber->Length); if (!certIssuerAndSN->serialNumber.Data) goto loser; PORT_Memcpy(certIssuerAndSN->serialNumber.Data, serialNumber->Data, serialNumber->Length); certIssuerAndSN->serialNumber.Length = serialNumber->Length; PORT_ArenaUnmark(pl, mark); CSSM_CL_FreeFieldValue(clHandle, &CSSMOID_X509V1SerialNumber, serialNumber); CSSM_CL_FreeFieldValue(clHandle, &OID_X509V1IssuerNameStd, issuer); return certIssuerAndSN; loser: PORT_ArenaRelease(pl, mark); if (serialNumber) CSSM_CL_FreeFieldValue(clHandle, &CSSMOID_X509V1SerialNumber, serialNumber); if (issuer) CSSM_CL_FreeFieldValue(clHandle, &OID_X509V1IssuerNameStd, issuer); PORT_SetError(SEC_INTERNAL_ONLY); return NULL; }