/* * Determine if specified identity's cert's issuer and serial number match the * provided issuer and serial number. Returns nonzero on match, else returns zero. */ static int pkinit_issuer_sn_match( SecIdentityRef idRef, const CSSM_DATA *matchIssuerSerial) { OSStatus ortn; SecCertificateRef certRef = NULL; CSSM_DATA INIT_CDATA(certIssuerSerial); int ourRtn = 0; assert(idRef != NULL); assert(matchIssuerSerial != NULL); /* Get this cert's issuer/serial number */ ortn = SecIdentityCopyCertificate(idRef, &certRef); if(ortn) { pkiCssmErr("SecIdentityCopyCertificate", ortn); return 0; } /* subsequent errors to errOut: */ ortn = pkinit_get_cert_issuer_sn(certRef, &certIssuerSerial); if(ortn) { pkiCssmErr("SecIdentityCopyCertificate", ortn); goto errOut; } ourRtn = pkiCompareCssmData(matchIssuerSerial, &certIssuerSerial) ? 1 : 0; errOut: if(certRef != NULL) { CFRelease(certRef); } if(certIssuerSerial.Data != NULL) { free(certIssuerSerial.Data); } return ourRtn; }
/* * Given a certificate, obtain the DER-encoded issuer and serial number. Result * is mallocd and must be freed by caller. */ static OSStatus pkinit_get_cert_issuer_sn( SecCertificateRef certRef, CSSM_DATA *issuerSerial) /* mallocd and RETURNED */ { OSStatus ortn; CSSM_DATA certData; krb5_data INIT_KDATA(issuerSerialKrb); krb5_data certDataKrb; krb5_error_code krtn; assert(certRef != NULL); assert(issuerSerial != NULL); ortn = SecCertificateGetData(certRef, &certData); if(ortn) { pkiCssmErr("SecCertificateGetData", ortn); return ortn; } PKI_CSSM_TO_KRB_DATA(&certData, &certDataKrb); krtn = krb5int_pkinit_get_issuer_serial(&certDataKrb, &issuerSerialKrb); if(krtn) { return CSSMERR_CL_INVALID_DATA; } PKI_KRB_TO_CSSM_DATA(&issuerSerialKrb, issuerSerial); return noErr; }
/* * Store the specified certificate (or, more likely, some platform-dependent * reference to it) as the specified principal's signing certificate. Passing * in NULL for the client_cert has the effect of deleting the relevant entry * in the cert storage. */ krb5_error_code krb5_pkinit_set_client_cert_from_signing_cert( const char *principal, /* full principal string */ krb5_pkinit_signing_cert_t client_cert) { SecIdentityRef idRef = (SecIdentityRef)client_cert; SecCertificateRef certRef = NULL; OSStatus ortn; krb5_error_code ourRtn = 0; if (NULL != idRef) { if (CFGetTypeID(idRef) != SecIdentityGetTypeID()) { ourRtn = KRB5KRB_ERR_GENERIC; goto fin; } /* Get the cert */ ortn = SecIdentityCopyCertificate(idRef, &certRef); if (ortn) { pkiCssmErr("SecIdentityCopyCertificate", ortn); ourRtn = KRB5KRB_ERR_GENERIC; goto fin; } } ourRtn = krb5_pkinit_set_client_cert(principal, (krb5_pkinit_cert_t)certRef); fin: if (certRef) CFRelease(certRef); return ourRtn; }
/* * Obtain signing cert for specified principal. On successful return, * caller must eventually release the cert with krb5_pkinit_release_cert(). */ krb5_error_code krb5_pkinit_get_client_cert( const char *principal, /* full principal string */ krb5_pkinit_signing_cert_t *client_cert) { CFDataRef issuerSerial = NULL; CSSM_DATA issuerSerialData; SecIdentityRef idRef = NULL; OSStatus ortn; CFDictionaryRef theDict = NULL; CFStringRef cfPrinc = NULL; krb5_error_code ourRtn = 0; if(principal == NULL) { return KRB5_PRINC_NOMATCH; } /* Is there a stored preference for PKINIT certs for this user? */ ortn = pkinit_get_pref_dict(&theDict); if(ortn) { return KRB5_PRINC_NOMATCH; } /* Entry in the dictionary for specified principal? */ cfPrinc = CFStringCreateWithCString(NULL, principal, kCFStringEncodingASCII); issuerSerial = (CFDataRef)CFDictionaryGetValue(theDict, cfPrinc); CFRelease(cfPrinc); if(issuerSerial == NULL) { pkiDebug("krb5_pkinit_get_client_cert: no identity found\n"); ourRtn = KRB5_PRINC_NOMATCH; goto errOut; } if(CFGetTypeID(issuerSerial) != CFDataGetTypeID()) { pkiDebug("krb5_pkinit_get_client_cert: bad kPkinitClientCertKey value\n"); ourRtn = KRB5_PRINC_NOMATCH; goto errOut; } issuerSerialData.Data = (uint8 *)CFDataGetBytePtr(issuerSerial); issuerSerialData.Length = CFDataGetLength(issuerSerial); /* find a cert with that issuer/serial number in default search list */ ortn = pkinit_search_ident(NULL, CSSM_KEYUSE_SIGN | CSSM_KEYUSE_ENCRYPT, &issuerSerialData, &idRef); if(ortn) { pkiDebug("krb5_pkinit_get_client_cert: no identity found!\n"); pkiCssmErr("pkinit_search_ident", ortn); ourRtn = KRB5_PRINC_NOMATCH; } else { *client_cert = (krb5_pkinit_signing_cert_t)idRef; } errOut: if(theDict) { CFRelease(theDict); } return ourRtn; }
/* * Convert CFArray of SecCertificateRefs to a mallocd array of krb5_datas. */ static krb5_error_code pkiCertArrayToKrb5Data( CFArrayRef cf_certs, unsigned *num_all_certs, krb5_data **all_certs) { CFIndex num_certs; krb5_data *allCerts = NULL; krb5_error_code krtn = 0; unsigned dex; if(cf_certs == NULL) { *all_certs = NULL; return 0; } num_certs = CFArrayGetCount(cf_certs); *num_all_certs = (unsigned)num_certs; if(num_certs == 0) { *all_certs = NULL; return 0; } allCerts = (krb5_data *)malloc(sizeof(krb5_data) * num_certs); if(allCerts == NULL) { return ENOMEM; } for(dex=0; dex<num_certs; dex++) { CSSM_DATA cert_data; OSStatus ortn; SecCertificateRef sec_cert; sec_cert = (SecCertificateRef)CFArrayGetValueAtIndex(cf_certs, dex); ortn = SecCertificateGetData(sec_cert, &cert_data); if(ortn) { pkiCssmErr("SecCertificateGetData", ortn); krtn = KRB5_PARSE_MALFORMED; break; } krtn = pkiCssmDataToKrb5Data(&cert_data, &allCerts[dex]); if(krtn) { break; } } if(krtn) { if(allCerts) { free(allCerts); } } else { *all_certs = allCerts; } return krtn; }
/* * In Mac OS terms, get the keychain on which a given identity resides. */ static krb5_error_code pkinit_cert_to_db( krb5_pkinit_signing_cert_t idRef, krb5_pkinit_cert_db_t *dbRef) { SecKeychainRef kcRef = NULL; SecKeyRef keyRef = NULL; OSStatus ortn; /* that's an identity - get the associated key's keychain */ ortn = SecIdentityCopyPrivateKey((SecIdentityRef)idRef, &keyRef); if(ortn) { pkiCssmErr("SecIdentityCopyPrivateKey", ortn); return ortn; } ortn = SecKeychainItemCopyKeychain((SecKeychainItemRef)keyRef, &kcRef); if(ortn) { pkiCssmErr("SecKeychainItemCopyKeychain", ortn); } else { *dbRef = (krb5_pkinit_cert_db_t)kcRef; } CFRelease(keyRef); return ortn; }
/* * Cook up a SecCertificateRef from a krb5_data. */ static OSStatus pkiKrb5DataToSecCert( const krb5_data *rawCert, SecCertificateRef *secCert) /* RETURNED */ { CSSM_DATA certData; OSStatus ortn; assert((rawCert != NULL) && (secCert != NULL)); certData.Data = (uint8 *)rawCert->data; certData.Length = rawCert->length; ortn = SecCertificateCreateFromData(&certData, CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER, secCert); if(ortn) { pkiCssmErr("SecCertificateCreateFromData", ortn); } return ortn; }
/* * Search specified keychain/array/NULL (NULL meaning the default search list) for * an Identity matching specified key usage and optional Issuer/Serial number. * If issuer/serial is specified and no identities match, or if no identities found * matching specified Key usage, errSecItemNotFound is returned. * * Caller must CFRelease a non-NULL returned idRef. */ static OSStatus pkinit_search_ident( CFTypeRef keychainOrArray, CSSM_KEYUSE keyUsage, const CSSM_DATA *issuerSerial, /* optional */ SecIdentityRef *foundId) /* RETURNED */ { OSStatus ortn; SecIdentityRef idRef = NULL; SecIdentitySearchRef srchRef = NULL; ortn = SecIdentitySearchCreate(keychainOrArray, keyUsage, &srchRef); if(ortn) { pkiCssmErr("SecIdentitySearchCreate", ortn); return ortn; } do { ortn = SecIdentitySearchCopyNext(srchRef, &idRef); if(ortn != noErr) { break; } if(issuerSerial == NULL) { /* no match needed, we're done - this is the KDC cert case */ break; } else if(pkinit_issuer_sn_match(idRef, issuerSerial)) { /* match, we're done */ break; } /* finished with this one */ CFRelease(idRef); idRef = NULL; } while(ortn == noErr); CFRelease(srchRef); if(idRef == NULL) { return errSecItemNotFound; } else { *foundId = idRef; return noErr; } }
/* * Obtain the KDC signing cert, with optional CA and specific cert specifiers. * CAs and cert specifiers are in the form of DER-encoded issuerAndSerialNumbers. * * The client_spec argument is typically provided by the client as kdcPkId. */ krb5_error_code krb5_pkinit_get_kdc_cert( krb5_ui_4 num_trusted_CAs, /* sizeof *trusted_CAs */ krb5_data *trusted_CAs, /* optional */ krb5_data *client_spec, /* optional */ krb5_pkinit_signing_cert_t *kdc_cert) { SecIdentityRef idRef = NULL; OSStatus ortn; krb5_error_code ourRtn = 0; /* OS X: trusted_CAs and client_spec ignored */ ortn = SecIdentityCopySystemIdentity(kSecIdentityDomainKerberosKDC, &idRef, NULL); if(ortn) { pkiCssmErr("SecIdentityCopySystemIdentity", ortn); return KRB5_PRINC_NOMATCH; } *kdc_cert = (krb5_pkinit_signing_cert_t)idRef; return ourRtn; }
/* * Parse a ContentInfo as best we can. All return fields are optional. * If signer_cert_status is NULL on entry, NO signature or cert evaluation * will be performed. */ krb5_error_code krb5int_pkinit_parse_cms_msg( const krb5_data *content_info, krb5_pkinit_cert_db_t cert_db, /* may be required for SignedData */ krb5_boolean is_client_msg, /* TRUE : msg is from client */ krb5_boolean *is_signed, /* RETURNED */ krb5_boolean *is_encrypted, /* RETURNED */ krb5_data *raw_data, /* RETURNED */ krb5int_cms_content_type *inner_content_type,/* Returned, ContentType of */ /* EncapsulatedData */ krb5_data *signer_cert, /* RETURNED */ krb5int_cert_sig_status *signer_cert_status,/* RETURNED */ unsigned *num_all_certs, /* size of *all_certs RETURNED */ krb5_data **all_certs) /* entire cert chain RETURNED */ { SecPolicySearchRef policy_search = NULL; SecPolicyRef policy = NULL; OSStatus ortn; krb5_error_code krtn = 0; CMSDecoderRef decoder = NULL; size_t num_signers; CMSSignerStatus signer_status; OSStatus cert_verify_status; CFArrayRef cf_all_certs = NULL; int msg_is_signed = 0; if(content_info == NULL) { pkiDebug("krb5int_pkinit_parse_cms_msg: no ContentInfo\n"); return KRB5_CRYPTO_INTERNAL; } ortn = CMSDecoderCreate(&decoder); if(ortn) { return ENOMEM; } ortn = CMSDecoderUpdateMessage(decoder, content_info->data, content_info->length); if(ortn) { /* no verify yet, must be bad message */ krtn = KRB5_PARSE_MALFORMED; goto errOut; } ortn = CMSDecoderFinalizeMessage(decoder); if(ortn) { pkiCssmErr("CMSDecoderFinalizeMessage", ortn); krtn = KRB5_PARSE_MALFORMED; goto errOut; } /* expect zero or one signers */ ortn = CMSDecoderGetNumSigners(decoder, &num_signers); switch(num_signers) { case 0: msg_is_signed = 0; break; case 1: msg_is_signed = 1; break; default: krtn = KRB5_PARSE_MALFORMED; goto errOut; } /* * We need a cert verify policy even if we're not actually evaluating * the cert due to requirements in libsecurity_smime. */ ortn = SecPolicySearchCreate(CSSM_CERT_X_509v3, is_client_msg ? &CSSMOID_APPLE_TP_PKINIT_CLIENT : &CSSMOID_APPLE_TP_PKINIT_SERVER, NULL, &policy_search); if(ortn) { pkiCssmErr("SecPolicySearchCreate", ortn); krtn = KRB5_CRYPTO_INTERNAL; goto errOut; } ortn = SecPolicySearchCopyNext(policy_search, &policy); if(ortn) { pkiCssmErr("SecPolicySearchCopyNext", ortn); krtn = KRB5_CRYPTO_INTERNAL; goto errOut; } /* get some basic status that doesn't need heavyweight evaluation */ if(msg_is_signed) { if(is_signed) { *is_signed = TRUE; } if(inner_content_type) { CSSM_OID ec_oid = {0, NULL}; CFDataRef ec_data = NULL; krb5int_cms_content_type ctype; ortn = CMSDecoderCopyEncapsulatedContentType(decoder, &ec_data); if(ortn || (ec_data == NULL)) { pkiCssmErr("CMSDecoderCopyEncapsulatedContentType", ortn); krtn = KRB5_CRYPTO_INTERNAL; goto errOut; } ec_oid.Data = (uint8 *)CFDataGetBytePtr(ec_data); ec_oid.Length = CFDataGetLength(ec_data); if(pkiCompareCssmData(&ec_oid, &CSSMOID_PKCS7_Data)) { ctype = ECT_Data; } else if(pkiCompareCssmData(&ec_oid, &CSSMOID_PKCS7_SignedData)) { ctype = ECT_SignedData; } else if(pkiCompareCssmData(&ec_oid, &CSSMOID_PKCS7_EnvelopedData)) { ctype = ECT_EnvelopedData; } else if(pkiCompareCssmData(&ec_oid, &CSSMOID_PKCS7_EncryptedData)) { ctype = ECT_EncryptedData; } else if(pkiCompareCssmData(&ec_oid, &_CSSMOID_PKINIT_AUTH_DATA)) { ctype = ECT_PkAuthData; } else if(pkiCompareCssmData(&ec_oid, &_CSSMOID_PKINIT_RKEY_DATA)) { ctype = ECT_PkReplyKeyKata; } else { ctype = ECT_Other; } *inner_content_type = ctype; CFRelease(ec_data); } /* * Get SignedData's certs if the caller wants them */ if(all_certs) { ortn = CMSDecoderCopyAllCerts(decoder, &cf_all_certs); if(ortn) { pkiCssmErr("CMSDecoderCopyAllCerts", ortn); krtn = KRB5_CRYPTO_INTERNAL; goto errOut; } krtn = pkiCertArrayToKrb5Data(cf_all_certs, num_all_certs, all_certs); if(krtn) { goto errOut; } } /* optional signer cert */ if(signer_cert) { SecCertificateRef sec_signer_cert = NULL; CSSM_DATA cert_data; ortn = CMSDecoderCopySignerCert(decoder, 0, &sec_signer_cert); if(ortn) { /* should never happen if it's signed */ pkiCssmErr("CMSDecoderCopySignerStatus", ortn); krtn = KRB5_CRYPTO_INTERNAL; goto errOut; } ortn = SecCertificateGetData(sec_signer_cert, &cert_data); if(ortn) { pkiCssmErr("SecCertificateGetData", ortn); CFRelease(sec_signer_cert); krtn = KRB5_CRYPTO_INTERNAL; goto errOut; } krtn = pkiDataToKrb5Data(cert_data.Data, cert_data.Length, signer_cert); CFRelease(sec_signer_cert); if(krtn) { goto errOut; } } } else { /* not signed */ if(is_signed) { *is_signed = FALSE; } if(inner_content_type) { *inner_content_type = ECT_Other; } if(signer_cert) { signer_cert->data = NULL; signer_cert->length = 0; } if(signer_cert_status) { *signer_cert_status = pki_not_signed; } if(num_all_certs) { *num_all_certs = 0; } if(all_certs) { *all_certs = NULL; } } if(is_encrypted) { Boolean bencr; ortn = CMSDecoderIsContentEncrypted(decoder, &bencr); if(ortn) { pkiCssmErr("CMSDecoderCopySignerStatus", ortn); krtn = KRB5_CRYPTO_INTERNAL; goto errOut; } *is_encrypted = bencr ? TRUE : FALSE; } /* * Verify signature and cert. The actual verify operation is optional, * per our signer_cert_status argument, but we do this anyway if we need * to get the signer cert. */ if((signer_cert_status != NULL) || (signer_cert != NULL)) { ortn = CMSDecoderCopySignerStatus(decoder, 0, /* signerIndex */ policy, signer_cert_status ? TRUE : FALSE, /* evaluateSecTrust */ &signer_status, NULL, /* secTrust - not needed */ &cert_verify_status); if(ortn) { /* gross error - subsequent processing impossible */ pkiCssmErr("CMSDecoderCopySignerStatus", ortn); krtn = KRB5_PARSE_MALFORMED; goto errOut; } } /* obtain & return status */ if(signer_cert_status) { *signer_cert_status = pkiInferSigStatus(signer_status, cert_verify_status); } /* finally, the payload */ if(raw_data) { CFDataRef cf_content = NULL; ortn = CMSDecoderCopyContent(decoder, &cf_content); if(ortn) { pkiCssmErr("CMSDecoderCopyContent", ortn); krtn = KRB5_PARSE_MALFORMED; goto errOut; } krtn = pkiCfDataToKrb5Data(cf_content, raw_data); CFRELEASE(cf_content); } errOut: CFRELEASE(policy_search); CFRELEASE(policy); CFRELEASE(cf_all_certs); CFRELEASE(decoder); return krtn; }
/* * Create a CMS message: either encrypted (EnvelopedData), signed * (SignedData), or both (EnvelopedData(SignedData(content)). * * The message is signed iff signing_cert is non-NULL. * The message is encrypted iff recip_cert is non-NULL. * * The content_type argument specifies to the eContentType * for a SignedData's EncapsulatedContentInfo. */ krb5_error_code krb5int_pkinit_create_cms_msg( const krb5_data *content, /* Content */ krb5_pkinit_signing_cert_t signing_cert, /* optional: signed by this cert */ const krb5_data *recip_cert, /* optional: encrypted with this cert */ krb5int_cms_content_type content_type, /* OID for EncapsulatedData */ krb5_ui_4 num_cms_types, /* optional, unused here */ const krb5int_algorithm_id *cms_types, /* optional, unused here */ krb5_data *content_info) /* contents mallocd and RETURNED */ { krb5_error_code krtn; OSStatus ortn; SecCertificateRef sec_recip = NULL; CFDataRef cf_content = NULL; const CSSM_OID *eContentOid = NULL; if((signing_cert == NULL) && (recip_cert == NULL)) { /* must have one or the other */ pkiDebug("krb5int_pkinit_create_cms_msg: no signer or recipient\n"); return KRB5_CRYPTO_INTERNAL; } /* * Optional signer cert. Note signing_cert, if present, is * a SecIdentityRef. */ if(recip_cert) { if(pkiKrb5DataToSecCert(recip_cert, &sec_recip)) { krtn = ASN1_BAD_FORMAT; goto errOut; } } /* optional eContentType */ if(signing_cert) { switch(content_type) { case ECT_PkAuthData: eContentOid = &_CSSMOID_PKINIT_AUTH_DATA; break; case ECT_PkReplyKeyKata: eContentOid = &_CSSMOID_PKINIT_RKEY_DATA; break; case ECT_Data: /* the only standard/default case we allow */ break; default: /* others: no can do */ pkiDebug("krb5int_pkinit_create_cms_msg: bad contentType\n"); krtn = KRB5_CRYPTO_INTERNAL; goto errOut; } } /* GO */ ortn = CMSEncode((SecIdentityRef)signing_cert, sec_recip, eContentOid, FALSE, /* detachedContent */ kCMSAttrNone, /* no signed attributes that I know of */ content->data, content->length, &cf_content); if(ortn) { pkiCssmErr("CMSEncode", ortn); krtn = KRB5_CRYPTO_INTERNAL; goto errOut; } krtn = pkiCfDataToKrb5Data(cf_content, content_info); errOut: CFRELEASE(sec_recip); CFRELEASE(cf_content); return krtn; }
/* * Parse PA-PK-AS-REP message. Optionally evaluates the message's certificate chain. * Optionally returns various components. */ krb5_error_code krb5int_pkinit_as_rep_parse( krb5_context context, const krb5_data *as_rep, krb5_pkinit_signing_cert_t client_cert, /* required */ krb5_keyblock *key_block, /* RETURNED */ krb5_checksum *checksum, /* checksum of corresponding AS-REQ */ /* contents mallocd and RETURNED */ krb5int_cert_sig_status *cert_status, /* RETURNED */ /* * Cert fields, all optionally RETURNED. * * signer_cert is the full X.509 leaf cert from the incoming SignedData. * all_certs is an array of all of the certs in the incoming SignedData, * in full X.509 form. */ krb5_data *signer_cert, /* content mallocd */ unsigned *num_all_certs, /* sizeof *all_certs */ krb5_data **all_certs) /* krb5_data's and their content mallocd */ { krb5_data reply_key_pack = {0, 0, NULL}; krb5_error_code krtn; krb5_data enc_key_pack = {0, 0, NULL}; krb5_data dh_signed_data = {0, 0, NULL}; krb5int_cms_content_type content_type; krb5_pkinit_cert_db_t cert_db = NULL; krb5_boolean is_signed; krb5_boolean is_encrypted; assert((as_rep != NULL) && (checksum != NULL) && (key_block != NULL) && (cert_status != NULL)); /* * Decode the top-level PA-PK-AS-REP */ krtn = krb5int_pkinit_pa_pk_as_rep_decode(as_rep, &dh_signed_data, &enc_key_pack); if(krtn) { pkiCssmErr("krb5int_pkinit_pa_pk_as_rep_decode", krtn); return krtn; } if(dh_signed_data.data) { /* not for this implementation... */ pkiDebug("krb5int_pkinit_as_rep_parse: unexpected dh_signed_data\n"); krtn = ASN1_BAD_FORMAT; goto err_out; } if(enc_key_pack.data == NULL) { /* REQUIRED for this implementation... */ pkiDebug("krb5int_pkinit_as_rep_parse: no enc_key_pack\n"); krtn = ASN1_BAD_FORMAT; goto err_out; } krtn = krb5_pkinit_get_client_cert_db(NULL, client_cert, &cert_db); if(krtn) { pkiDebug("krb5int_pkinit_as_rep_parse: error in krb5_pkinit_get_client_cert_db\n"); goto err_out; } /* * enc_key_pack is an EnvelopedData(SignedData(keyPack), encrypted * with our cert (which krb5int_pkinit_parse_content_info() finds * implicitly). */ krtn = krb5int_pkinit_parse_cms_msg(&enc_key_pack, cert_db, FALSE, &is_signed, &is_encrypted, &reply_key_pack, &content_type, signer_cert, cert_status, num_all_certs, all_certs); if(krtn) { pkiDebug("krb5int_pkinit_as_rep_parse: error decoding EnvelopedData\n"); goto err_out; } if(!is_encrypted || !is_signed) { pkiDebug("krb5int_pkinit_as_rep_parse: not signed and encrypted!\n"); krtn = KRB5_PARSE_MALFORMED; goto err_out; } if(content_type != ECT_PkReplyKeyKata) { pkiDebug("replyKeyPack eContentType %d!\n", (int)content_type); krtn = KRB5_PARSE_MALFORMED; goto err_out; } /* * Finally, decode that inner content as the ReplyKeyPack which contains * the actual key and nonce */ krtn = krb5int_pkinit_reply_key_pack_decode(&reply_key_pack, key_block, checksum); if(krtn) { pkiDebug("krb5int_pkinit_as_rep_parse: error decoding ReplyKeyPack\n"); } err_out: /* free temp mallocd data that we didn't pass back to caller */ if(reply_key_pack.data) { free(reply_key_pack.data); } if(enc_key_pack.data) { free(enc_key_pack.data); } if(dh_signed_data.data) { free(dh_signed_data.data); } if(cert_db) { krb5_pkinit_release_cert_db(cert_db); } return krtn; }
/* * Given a DER encoded certificate, obtain the associated IssuerAndSerialNumber. */ krb5_error_code krb5int_pkinit_get_issuer_serial( const krb5_data *cert, krb5_data *issuer_and_serial) { CSSM_HANDLE cacheHand = 0; CSSM_RETURN crtn = CSSM_OK; CSSM_DATA certData = { cert->length, (uint8 *)cert->data }; CSSM_HANDLE resultHand = 0; CSSM_DATA_PTR derIssuer = NULL; CSSM_DATA_PTR serial; krb5_data krb_serial; krb5_data krb_issuer; uint32 numFields; krb5_error_code ourRtn = 0; CSSM_CL_HANDLE clHand = pkiClStartup(); if(clHand == 0) { return CSSMERR_CSSM_ADDIN_LOAD_FAILED; } /* subsequent errors to errOut: */ crtn = CSSM_CL_CertCache(clHand, &certData, &cacheHand); if(crtn) { pkiCssmErr("CSSM_CL_CertCache", crtn); ourRtn = ASN1_PARSE_ERROR; goto errOut; } /* obtain the two fields; issuer is DER encoded */ crtn = CSSM_CL_CertGetFirstCachedFieldValue(clHand, cacheHand, &CSSMOID_X509V1IssuerNameStd, &resultHand, &numFields, &derIssuer); if(crtn) { pkiCssmErr("CSSM_CL_CertGetFirstCachedFieldValue(issuer)", crtn); ourRtn = ASN1_PARSE_ERROR; goto errOut; } crtn = CSSM_CL_CertGetFirstCachedFieldValue(clHand, cacheHand, &CSSMOID_X509V1SerialNumber, &resultHand, &numFields, &serial); if(crtn) { pkiCssmErr("CSSM_CL_CertGetFirstCachedFieldValue(serial)", crtn); ourRtn = ASN1_PARSE_ERROR; goto errOut; } PKI_CSSM_TO_KRB_DATA(derIssuer, &krb_issuer); PKI_CSSM_TO_KRB_DATA(serial, &krb_serial); ourRtn = krb5int_pkinit_issuer_serial_encode(&krb_issuer, &krb_serial, issuer_and_serial); errOut: if(derIssuer) { CSSM_CL_FreeFieldValue(clHand, &CSSMOID_X509V1IssuerNameStd, derIssuer); } if(serial) { CSSM_CL_FreeFieldValue(clHand, &CSSMOID_X509V1SerialNumber, serial); } if(cacheHand) { CSSM_CL_CertAbortCache(clHand, cacheHand); } if(clHand) { pkiClDetachUnload(clHand); } return ourRtn; }