/* * Decode a KRB5_PA_PK_AS_REP. */ krb5_error_code krb5int_pkinit_pa_pk_as_rep_decode( const krb5_data *pa_pk_as_rep, krb5_data *dh_signed_data, krb5_data *enc_key_pack) { KRB5_PA_PK_AS_REP asRep; SecAsn1CoderRef coder; CSSM_DATA der = {pa_pk_as_rep->length, (uint8 *)pa_pk_as_rep->data}; krb5_error_code ourRtn = 0; /* Decode --> KRB5_PA_PK_AS_REP */ if(SecAsn1CoderCreate(&coder)) { return ENOMEM; } memset(&asRep, 0, sizeof(asRep)); if(SecAsn1DecodeData(coder, &der, KRB5_PA_PK_AS_REPTemplate, &asRep)) { ourRtn = ASN1_BAD_FORMAT; goto errOut; } if(asRep.dhSignedData) { if((ourRtn = pkiCssmDataToKrb5Data(asRep.dhSignedData, dh_signed_data))) { goto errOut; } } if(asRep.encKeyPack) { ourRtn = pkiCssmDataToKrb5Data(asRep.encKeyPack, enc_key_pack); } errOut: SecAsn1CoderRelease(coder); return ourRtn; }
/* * Decode IssuerAndSerialNumber. */ krb5_error_code krb5int_pkinit_issuer_serial_decode( const krb5_data *issuer_and_serial, /* DER encoded */ krb5_data *issuer, /* DER encoded, RETURNED */ krb5_data *serial_num) /* RETURNED */ { KRB5_IssuerAndSerial issuerSerial; SecAsn1CoderRef coder; CSSM_DATA der = {issuer_and_serial->length, (uint8 *)issuer_and_serial->data}; krb5_error_code ourRtn = 0; /* Decode --> issuerSerial */ if(SecAsn1CoderCreate(&coder)) { return ENOMEM; } memset(&issuerSerial, 0, sizeof(issuerSerial)); if(SecAsn1DecodeData(coder, &der, KRB5_IssuerAndSerialTemplate, &issuerSerial)) { ourRtn = ASN1_BAD_FORMAT; goto errOut; } /* Convert KRB5_IssuerAndSerial to caller's params */ if((ourRtn = pkiCssmDataToKrb5Data(&issuerSerial.derIssuer, issuer))) { goto errOut; } if((ourRtn = pkiCssmDataToKrb5Data(&issuerSerial.serialNumber, serial_num))) { ourRtn = ENOMEM; goto errOut; } errOut: SecAsn1CoderRelease(coder); return ourRtn; }
/* * 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; }
/* * 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; }
/* * Decode a ReplyKeyPack. */ krb5_error_code krb5int_pkinit_reply_key_pack_decode( const krb5_data *reply_key_pack, krb5_keyblock *key_block, /* RETURNED */ krb5_checksum *checksum) /* contents mallocd and RETURNED */ { KRB5_ReplyKeyPack repKeyPack; SecAsn1CoderRef coder; krb5_error_code ourRtn = 0; KRB5_EncryptionKey *encryptKey = &repKeyPack.encryptionKey; CSSM_DATA der = {reply_key_pack->length, (uint8 *)reply_key_pack->data}; krb5_data tmpData; KRB5_Checksum *cksum = &repKeyPack.asChecksum; /* Decode --> KRB5_ReplyKeyPack */ if(SecAsn1CoderCreate(&coder)) { return ENOMEM; } memset(&repKeyPack, 0, sizeof(repKeyPack)); if(SecAsn1DecodeData(coder, &der, KRB5_ReplyKeyPackTemplate, &repKeyPack)) { ourRtn = ASN1_BAD_FORMAT; goto errOut; } if((ourRtn = pkiDataToInt(&encryptKey->keyType, (krb5_int32 *)&key_block->enctype))) { goto errOut; } if((ourRtn = pkiCssmDataToKrb5Data(&encryptKey->keyValue, &tmpData))) { goto errOut; } key_block->contents = (krb5_octet *)tmpData.data; key_block->length = tmpData.length; if((ourRtn = pkiDataToInt(&cksum->checksumType, &checksum->checksum_type))) { goto errOut; } checksum->contents = (krb5_octet *)malloc(cksum->checksum.Length); if(checksum->contents == NULL) { ourRtn = ENOMEM; goto errOut; } checksum->length = cksum->checksum.Length; memmove(checksum->contents, cksum->checksum.Data, checksum->length); checksum->magic = KV5M_CHECKSUM; errOut: SecAsn1CoderRelease(coder); return ourRtn; }
/* * Encode a ReplyKeyPack. The result is used as the Content of a SignedData. */ krb5_error_code krb5int_pkinit_reply_key_pack_encode( const krb5_keyblock *key_block, const krb5_checksum *checksum, krb5_data *reply_key_pack) /* mallocd and RETURNED */ { KRB5_ReplyKeyPack repKeyPack; SecAsn1CoderRef coder; krb5_error_code ourRtn = 0; CSSM_DATA der = {0, NULL}; OSStatus ortn; KRB5_EncryptionKey *encryptKey = &repKeyPack.encryptionKey; KRB5_Checksum *cksum = &repKeyPack.asChecksum; if(SecAsn1CoderCreate(&coder)) { return ENOMEM; } memset(&repKeyPack, 0, sizeof(repKeyPack)); if((ourRtn = pkiIntToData(key_block->enctype, &encryptKey->keyType, coder))) { goto errOut; } encryptKey->keyValue.Length = key_block->length, encryptKey->keyValue.Data = (uint8 *)key_block->contents; if((ourRtn = pkiIntToData(checksum->checksum_type, &cksum->checksumType, coder))) { goto errOut; } cksum->checksum.Data = (uint8 *)checksum->contents; cksum->checksum.Length = checksum->length; ortn = SecAsn1EncodeItem(coder, &repKeyPack, KRB5_ReplyKeyPackTemplate, &der); if(ortn) { ourRtn = ENOMEM; goto errOut; } ourRtn = pkiCssmDataToKrb5Data(&der, reply_key_pack); errOut: SecAsn1CoderRelease(coder); return ourRtn; }
/* * 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; }
/* * Encode AuthPack, public key version (no Diffie-Hellman components). */ krb5_error_code krb5int_pkinit_auth_pack_encode( krb5_timestamp kctime, krb5_int32 cusec, /* microseconds */ krb5_ui_4 nonce, const krb5_checksum *pa_checksum, const krb5int_algorithm_id *cms_types, /* optional */ krb5_ui_4 num_cms_types, krb5_data *auth_pack) /* mallocd and RETURNED */ { KRB5_AuthPack localAuthPack; SecAsn1CoderRef coder; CSSM_DATA *cksum = &localAuthPack.pkAuth.paChecksum; krb5_error_code ourRtn = 0; CSSM_DATA ber = {0, NULL}; OSStatus ortn; char *timeStr = NULL; if(SecAsn1CoderCreate(&coder)) { return ENOMEM; } memset(&localAuthPack, 0, sizeof(localAuthPack)); if(pkiKrbTimestampToStr(kctime, &timeStr)) { ourRtn = -1; goto errOut; } localAuthPack.pkAuth.kctime.Data = (uint8 *)timeStr; localAuthPack.pkAuth.kctime.Length = strlen(timeStr); if(pkiIntToData(cusec, &localAuthPack.pkAuth.cusec, coder)) { ourRtn = ENOMEM; goto errOut; } if(pkiIntToData(nonce, &localAuthPack.pkAuth.nonce, coder)) { ourRtn = ENOMEM; goto errOut; } cksum->Data = (uint8 *)pa_checksum->contents; cksum->Length = pa_checksum->length; if((cms_types != NULL) && (num_cms_types != 0)) { unsigned dex; CSSM_X509_ALGORITHM_IDENTIFIER **algIds; /* build a NULL_terminated array of CSSM_X509_ALGORITHM_IDENTIFIERs */ localAuthPack.supportedCMSTypes = (CSSM_X509_ALGORITHM_IDENTIFIER **) SecAsn1Malloc(coder, (num_cms_types + 1) * sizeof(CSSM_X509_ALGORITHM_IDENTIFIER *)); algIds = localAuthPack.supportedCMSTypes; for(dex=0; dex<num_cms_types; dex++) { algIds[dex] = (CSSM_X509_ALGORITHM_IDENTIFIER *) SecAsn1Malloc(coder, sizeof(CSSM_X509_ALGORITHM_IDENTIFIER)); pkiKrb5DataToCssm(&cms_types[dex].algorithm, &algIds[dex]->algorithm, coder); if(cms_types[dex].parameters.data != NULL) { pkiKrb5DataToCssm(&cms_types[dex].parameters, &algIds[dex]->parameters, coder); } else { algIds[dex]->parameters.Data = NULL; algIds[dex]->parameters.Length = 0; } } algIds[num_cms_types] = NULL; } ortn = SecAsn1EncodeItem(coder, &localAuthPack, KRB5_AuthPackTemplate, &ber); if(ortn) { ourRtn = ENOMEM; goto errOut; } if(pkiCssmDataToKrb5Data(&ber, auth_pack)) { ourRtn = ENOMEM; } else { auth_pack->magic = KV5M_AUTHENTICATOR; ourRtn = 0; } errOut: SecAsn1CoderRelease(coder); return ourRtn; }