/* * Given DER-encoded issuer and serial number, create an encoded * IssuerAndSerialNumber. */ krb5_error_code krb5int_pkinit_issuer_serial_encode( const krb5_data *issuer, /* DER encoded */ const krb5_data *serial_num, krb5_data *issuer_and_serial) /* content mallocd and RETURNED */ { KRB5_IssuerAndSerial issuerSerial; SecAsn1CoderRef coder; CSSM_DATA ber = {0, NULL}; OSStatus ortn; if(SecAsn1CoderCreate(&coder)) { return ENOMEM; } PKI_KRB_TO_CSSM_DATA(issuer, &issuerSerial.derIssuer); PKI_KRB_TO_CSSM_DATA(serial_num, &issuerSerial.serialNumber); ortn = SecAsn1EncodeItem(coder, &issuerSerial, KRB5_IssuerAndSerialTemplate, &ber); if(ortn) { ortn = ENOMEM; goto errOut; } ortn = pkiCssmDataToKrb5Data(&ber, issuer_and_serial); errOut: SecAsn1CoderRelease(coder); return ortn; }
/* * 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; }
/* * Encode a KRB5_PA_PK_AS_REP. */ krb5_error_code krb5int_pkinit_pa_pk_as_rep_encode( const krb5_data *dh_signed_data, const krb5_data *enc_key_pack, krb5_data *pa_pk_as_rep) /* mallocd and RETURNED */ { KRB5_PA_PK_AS_REP asRep; SecAsn1CoderRef coder; krb5_error_code ourRtn = 0; CSSM_DATA der = {0, NULL}; OSStatus ortn; CSSM_DATA dhSignedData; CSSM_DATA encKeyPack; if(SecAsn1CoderCreate(&coder)) { return ENOMEM; } memset(&asRep, 0, sizeof(asRep)); if(dh_signed_data) { PKI_KRB_TO_CSSM_DATA(dh_signed_data, &dhSignedData); asRep.dhSignedData = &dhSignedData; } if(enc_key_pack) { PKI_KRB_TO_CSSM_DATA(enc_key_pack, &encKeyPack); asRep.encKeyPack = &encKeyPack; } ortn = SecAsn1EncodeItem(coder, &asRep, KRB5_PA_PK_AS_REPTemplate, &der); if(ortn) { ourRtn = ENOMEM; goto errOut; } ourRtn = pkiCssmDataToKrb5Data(&der, pa_pk_as_rep); errOut: SecAsn1CoderRelease(coder); return ourRtn; }
/* * Top-level decode for PA-PK-AS-REQ. */ krb5_error_code krb5int_pkinit_pa_pk_as_req_decode( const krb5_data *pa_pk_as_req, krb5_data *signed_auth_pack, /* DER encoded ContentInfo, RETURNED */ /* * Remainder are optionally RETURNED (specify NULL for pointers to * items you're not interested in). */ krb5_ui_4 *num_trusted_CAs, /* sizeof trusted_CAs */ krb5_data **trusted_CAs, /* mallocd array of DER-encoded TrustedCAs issuer/serial */ krb5_data *kdc_cert) /* DER encoded issuer/serial */ { KRB5_PA_PK_AS_REQ asReq; SecAsn1CoderRef coder; CSSM_DATA der; krb5_error_code ourRtn = 0; assert(pa_pk_as_req != NULL); /* Decode --> KRB5_PA_PK_AS_REQ */ if(SecAsn1CoderCreate(&coder)) { return ENOMEM; } PKI_KRB_TO_CSSM_DATA(pa_pk_as_req, &der); memset(&asReq, 0, sizeof(asReq)); if(SecAsn1DecodeData(coder, &der, KRB5_PA_PK_AS_REQTemplate, &asReq)) { ourRtn = ASN1_BAD_FORMAT; goto errOut; } /* Convert decoded results to caller's args; each is optional */ if(signed_auth_pack != NULL) { if((ourRtn = pkiCssmDataToKrb5Data(&asReq.signedAuthPack, signed_auth_pack))) { goto errOut; } } if(asReq.trusted_CAs && (trusted_CAs != NULL)) { /* NULL-terminated array of CSSM_DATA ptrs */ unsigned numCas = pkiNssArraySize((const void **)asReq.trusted_CAs); unsigned dex; krb5_data *kdcCas; kdcCas = (krb5_data *)malloc(sizeof(krb5_data) * numCas); if(kdcCas == NULL) { ourRtn = ENOMEM; goto errOut; } for(dex=0; dex<numCas; dex++) { KRB5_ExternalPrincipalIdentifier *epi = asReq.trusted_CAs[dex]; if(epi->issuerAndSerialNumber.Data) { /* the only variant we support */ pkiCssmDataToKrb5Data(&epi->issuerAndSerialNumber, &kdcCas[dex]); } } *trusted_CAs = kdcCas; *num_trusted_CAs = numCas; } if(asReq.kdcPkId.Data && kdc_cert) { if((ourRtn = pkiCssmDataToKrb5Data(&asReq.kdcPkId, kdc_cert))) { goto errOut; } } errOut: SecAsn1CoderRelease(coder); return ourRtn; }
/* * Top-level encode for PA-PK-AS-REQ. */ krb5_error_code krb5int_pkinit_pa_pk_as_req_encode( const krb5_data *signed_auth_pack, /* DER encoded ContentInfo */ const krb5_data *trusted_CAs, /* optional: trustedCertifiers. Contents are * DER-encoded issuer/serialNumbers. */ krb5_ui_4 num_trusted_CAs, const krb5_data *kdc_cert, /* optional kdcPkId, DER encoded issuer/serial */ krb5_data *pa_pk_as_req) /* mallocd and RETURNED */ { KRB5_PA_PK_AS_REQ req; SecAsn1CoderRef coder; CSSM_DATA ber = {0, NULL}; OSStatus ortn; unsigned dex; assert(signed_auth_pack != NULL); assert(pa_pk_as_req != NULL); if(SecAsn1CoderCreate(&coder)) { return ENOMEM; } /* krb5_data ==> CSSM format */ memset(&req, 0, sizeof(req)); PKI_KRB_TO_CSSM_DATA(signed_auth_pack, &req.signedAuthPack); if(num_trusted_CAs) { /* * Set up a NULL-terminated array of KRB5_ExternalPrincipalIdentifier * pointers. We malloc the actual KRB5_ExternalPrincipalIdentifiers as * a contiguous array; it's in temp SecAsn1CoderRef memory. The referents * are just dropped in from the caller's krb5_datas. */ KRB5_ExternalPrincipalIdentifier *cas = (KRB5_ExternalPrincipalIdentifier *)SecAsn1Malloc(coder, num_trusted_CAs * sizeof(KRB5_ExternalPrincipalIdentifier)); req.trusted_CAs = (KRB5_ExternalPrincipalIdentifier **) pkiNssNullArray(num_trusted_CAs, coder); for(dex=0; dex<num_trusted_CAs; dex++) { req.trusted_CAs[dex] = &cas[dex]; memset(&cas[dex], 0, sizeof(KRB5_ExternalPrincipalIdentifier)); PKI_KRB_TO_CSSM_DATA(&trusted_CAs[dex], &cas[dex].issuerAndSerialNumber); } } if(kdc_cert) { PKI_KRB_TO_CSSM_DATA(kdc_cert, &req.kdcPkId); } /* encode */ ortn = SecAsn1EncodeItem(coder, &req, KRB5_PA_PK_AS_REQTemplate, &ber); if(ortn) { ortn = ENOMEM; goto errOut; } ortn = pkiCssmDataToKrb5Data(&ber, pa_pk_as_req); errOut: SecAsn1CoderRelease(coder); return ortn; }
/* * Decode AuthPack, public key version (no Diffie-Hellman components). */ krb5_error_code krb5int_pkinit_auth_pack_decode( const krb5_data *auth_pack, /* DER encoded */ krb5_timestamp *kctime, /* RETURNED */ krb5_ui_4 *cusec, /* microseconds, RETURNED */ krb5_ui_4 *nonce, /* RETURNED */ krb5_checksum *pa_checksum, /* contents mallocd and RETURNED */ krb5int_algorithm_id **cms_types, /* optionally mallocd and RETURNED */ krb5_ui_4 *num_cms_types) /* optionally RETURNED */ { KRB5_AuthPack localAuthPack; SecAsn1CoderRef coder; CSSM_DATA der = {0, NULL}; krb5_error_code ourRtn = 0; CSSM_DATA *cksum = &localAuthPack.pkAuth.paChecksum; /* Decode --> localAuthPack */ if(SecAsn1CoderCreate(&coder)) { return ENOMEM; } PKI_KRB_TO_CSSM_DATA(auth_pack, &der); memset(&localAuthPack, 0, sizeof(localAuthPack)); if(SecAsn1DecodeData(coder, &der, KRB5_AuthPackTemplate, &localAuthPack)) { ourRtn = ASN1_BAD_FORMAT; goto errOut; } /* optionally Convert KRB5_AuthPack to caller's params */ if(kctime) { if((ourRtn = pkiTimeStrToKrbTimestamp((char *)localAuthPack.pkAuth.kctime.Data, localAuthPack.pkAuth.kctime.Length, kctime))) { goto errOut; } } if(cusec) { if((ourRtn = pkiDataToInt(&localAuthPack.pkAuth.cusec, (krb5_int32 *)cusec))) { goto errOut; } } if(nonce) { if((ourRtn = pkiDataToInt(&localAuthPack.pkAuth.nonce, (krb5_int32 *)nonce))) { goto errOut; } } if(pa_checksum) { if(cksum->Length == 0) { /* This is the unique error for "no paChecksum" */ ourRtn = KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED; goto errOut; } else { pa_checksum->contents = (krb5_octet *)malloc(cksum->Length); if(pa_checksum->contents == NULL) { ourRtn = ENOMEM; goto errOut; } pa_checksum->length = cksum->Length; memmove(pa_checksum->contents, cksum->Data, pa_checksum->length); pa_checksum->magic = KV5M_CHECKSUM; /* This used to be encoded with the checksum but no more... */ pa_checksum->checksum_type = CKSUMTYPE_NIST_SHA; } } if(cms_types) { if(localAuthPack.supportedCMSTypes == NULL) { *cms_types = NULL; *num_cms_types = 0; } else { /* * Convert NULL-terminated array of CSSM-style algIds to * krb5int_algorithm_ids. */ unsigned dex; unsigned num_types = 0; CSSM_X509_ALGORITHM_IDENTIFIER **alg_ids; krb5int_algorithm_id *kalg_ids; for(alg_ids=localAuthPack.supportedCMSTypes; *alg_ids; alg_ids++) { num_types++; } *cms_types = kalg_ids = (krb5int_algorithm_id *)calloc(num_types, sizeof(krb5int_algorithm_id)); *num_cms_types = num_types; alg_ids = localAuthPack.supportedCMSTypes; for(dex=0; dex<num_types; dex++) { if(alg_ids[dex]->algorithm.Data) { pkiCssmDataToKrb5Data(&alg_ids[dex]->algorithm, &kalg_ids[dex].algorithm); } if(alg_ids[dex]->parameters.Data) { pkiCssmDataToKrb5Data(&alg_ids[dex]->parameters, &kalg_ids[dex].parameters); } } } } ourRtn = 0; errOut: SecAsn1CoderRelease(coder); return ourRtn; }