/* * 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; }
/* * 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; }
/* * Print contents of an encoded Name (e.g. from an IssuerAndSerialNumber). */ void printName( const char *title, unsigned char *name, unsigned nameLen) { SecAsn1CoderRef coder; if(SecAsn1CoderCreate(&coder)) { printf("*****Screwup in SecAsn1CoderCreate\n"); return; } CSSM_DATA der = {nameLen, name}; NSS_Name nssName; if(SecAsn1DecodeData(coder, &der, kSecAsn1NameTemplate, &nssName)) { printf("***Error decoding %s\n", title); return; } printf(" %s:\n", title); unsigned numRdns = pkiNssArraySize((const void **)nssName.rdns); for(unsigned rdnDex=0; rdnDex<numRdns; rdnDex++) { NSS_RDN *rdn = nssName.rdns[rdnDex]; unsigned numAtvs = pkiNssArraySize((const void **)rdn->atvs); for(unsigned atvDex=0; atvDex<numAtvs; atvDex++) { printAtv(rdn->atvs[atvDex]); } } }
OSStatus SecPKCS12Import(CFDataRef pkcs12_data, CFDictionaryRef options, CFArrayRef *items) { pkcs12_context context = {}; SecAsn1CoderCreate(&context.coder); if (options) context.passphrase = CFDictionaryGetValue(options, kSecImportExportPassphrase); context.items = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); int status = p12decode(&context, pkcs12_data); if (!status) { CFMutableArrayRef certs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); CFDictionaryApplyFunction(context.items, collect_certs, certs); CFMutableArrayRef identities = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); build_trust_chains_context a_build_trust_chains_context = { identities, certs }; CFDictionaryApplyFunction(context.items, build_trust_chains, &a_build_trust_chains_context); CFReleaseSafe(certs); /* ignoring certs that weren't picked up as part of the certchain for found keys */ *items = identities; } CFReleaseSafe(context.items); SecAsn1CoderRelease(context.coder); switch (status) { case p12_noErr: return noErr; case p12_passwordErr: return errSecAuthFailed; case p12_decodeErr: return errSecDecode; default: return errSecInternal; }; return noErr; }
int derDecodeInit( TestParams *testParams) { /* * DER encode a sequence of two integers */ twoInts ti; ti.int1.Data = int1; ti.int1.Length = sizeof(int1); ti.int2.Data = int2; ti.int2.Length = sizeof(int2); /* encode --> tempDer */ SecAsn1CoderRef coder; SecAsn1CoderCreate(&coder); CSSM_DATA tmpDer = {0, NULL}; if(SecAsn1EncodeItem(coder, &ti, twoIntsTemp, &tmpDer)) { printf("***derDecodeInit: Error on encodeItem()\n"); return -1; } /* copy to goodDer and badDer */ appCopyCssmData(&tmpDer, &goodDer); appCopyCssmData(&tmpDer, &badDer); /* increment the length of the outer sequence to force error */ badDer.Data[1]++; SecAsn1CoderRelease(coder); return 0; }
OCSPExtensions::OCSPExtensions( NSS_CertExtension **nssExts) : mCoder(NULL), mNumExtensions(0), mExtensions(NULL) { SecAsn1CoderCreate(&mCoder); mNumExtensions = ocspdArraySize((const void **)nssExts); if(mNumExtensions == 0) { return; } mExtensions = (OCSPExtension **)SecAsn1Malloc(mCoder, (mNumExtensions * sizeof(OCSPExtension *))); for(unsigned dex=0; dex<mNumExtensions; dex++) { try { mExtensions[dex] = OCSPExtension::createFromNSS(mCoder, *nssExts[dex]); if(mExtensions[dex] == NULL) { ocspdErrorLog("OCSPExtensions: extension failure (NULL) dex %u\n", dex); CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); } if(mExtensions[dex]->unrecognizedCritical()) { ocspdErrorLog("OCSPExtensions: unrecognized critical extension\n"); CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); } } catch (...) { ocspdErrorLog("OCSPExtensions: extension failure dex %u\n", dex); CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); } } }
/* print a CFData as an X509 Name (i.e., subject or issuer) */ void printCfName( CFDataRef nameData, OidParser &parser) { SecAsn1CoderRef coder = NULL; OSStatus ortn; ortn = SecAsn1CoderCreate(&coder); if(ortn) { cssmPerror("SecAsn1CoderCreate", ortn); return; } /* subsequent errors to errOut: */ NSS_Name nssName = {NULL}; unsigned numRdns; ortn = SecAsn1Decode(coder, CFDataGetBytePtr(nameData), CFDataGetLength(nameData), kSecAsn1NameTemplate, &nssName); if(ortn) { printf("***Error decoding NSS_Name\n"); goto errOut; } numRdns = nssArraySize((const void **)nssName.rdns); for(unsigned dex=0; dex<numRdns; dex++) { printRdn(nssName.rdns[dex], parser); } errOut: if(coder) { SecAsn1CoderRelease(coder); } }
/* * 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; }
int derDecodeTest(TestParams *testParams) { /* which flavor - good or bad? */ const CSSM_DATA *derSrc; bool expectErr = false; if((testParams->threadNum & 1) || !DO_BAD_DECODE) { derSrc = &goodDer; } else { derSrc = &badDer; expectErr = true; } for(unsigned loop=0; loop<testParams->numLoops; loop++) { if(testParams->verbose) { printf("derDecode thread %d: loop %d\n", testParams->threadNum, loop); } else if(!testParams->quiet) { printChar(testParams->progressChar); } for(unsigned dex=0; dex<DECODES_PER_LOOP; dex++) { SecAsn1CoderRef coder; SecAsn1CoderCreate(&coder); twoInts ti; OSStatus perr1, perr2; memset(&ti, 0, sizeof(ti)); perr1 = SecAsn1DecodeData(coder, derSrc, twoIntsTemp, &ti); usleep(100); perr2 = SecAsn1DecodeData(coder, derSrc, twoIntsTemp, &ti); if(perr1 != perr2) { printf("***derDecodeTest: different errors (%d, %d)\n", (int)perr1, (int)perr2); return 1; } if(expectErr) { if(!perr1) { printf("derDecodeTest: expect failure, got success\n"); return 1; } } else { if(perr1) { printf("derDecodeTest: expect success, got %d\n", (int)perr1); return 1; } } SecAsn1CoderRelease(coder); } #if DO_PAUSE fflush(stdin); printf("End of loop, CR to continue: "); getchar(); #endif } return 0; }
/* Fill out a CSSM_DATA with the subset of public key bytes from the given * CSSM_KEY_PTR which should be hashed to produce the issuerKeyHash field * of a CertID in an OCSP request. * * For RSA keys, this simply copies the input key pointer and length. * For EC keys, we need to further deconstruct the SubjectPublicKeyInfo * to obtain the key bytes (i.e. curve point) for hashing. * * Returns CSSM_OK on success, or non-zero error if the bytes could not * be retrieved. */ CSSM_RETURN ocspdGetPublicKeyBytes( SecAsn1CoderRef coder, // optional CSSM_KEY_PTR publicKey, // input public key CSSM_DATA &publicKeyBytes) // filled in by this function { CSSM_RETURN crtn = CSSM_OK; SecAsn1CoderRef _coder = NULL; if(publicKey == NULL) { crtn = CSSMERR_CSP_INVALID_KEY_POINTER; goto exit; } if(coder == NULL) { crtn = SecAsn1CoderCreate(&_coder); if(crtn) { goto exit; } coder = _coder; } publicKeyBytes.Length = publicKey->KeyData.Length; publicKeyBytes.Data = publicKey->KeyData.Data; if(publicKey->KeyHeader.AlgorithmId == CSSM_ALGID_ECDSA) { /* * For an EC key, publicKey->KeyData is a SubjectPublicKeyInfo * ASN.1 sequence that includes the algorithm identifier. * We only want to return the bit string portion of the key here. */ SecAsn1PubKeyInfo pkinfo; memset(&pkinfo, 0, sizeof(pkinfo)); if(SecAsn1Decode(coder, publicKey->KeyData.Data, publicKey->KeyData.Length, kSecAsn1SubjectPublicKeyInfoTemplate, &pkinfo) == 0) { if(pkinfo.subjectPublicKey.Length && pkinfo.subjectPublicKey.Data) { publicKeyBytes.Length = pkinfo.subjectPublicKey.Length >> 3; publicKeyBytes.Data = pkinfo.subjectPublicKey.Data; /* * Important: if we allocated the SecAsn1Coder, the memory * being pointed to by pkinfo.subjectPublicKey.Data will be * deallocated when the coder is released below. We want to * point to the identical data inside the caller's public key, * now that the decoder has identified it for us. */ if(publicKeyBytes.Length <= publicKey->KeyData.Length) { publicKeyBytes.Data = (uint8*)((uintptr_t)publicKey->KeyData.Data + (publicKey->KeyData.Length - publicKeyBytes.Length)); goto exit; } /* intentional fallthrough to error exit */ } ocspdErrorLog("ocspdGetPublicKeyBytes: invalid SecAsn1PubKeyInfo\n"); crtn = CSSMERR_CSP_INVALID_KEY_POINTER; }
/* * Following a CSSMOID_ECDSA_WithSpecified algorithm is an encoded * ECDSA_SigAlgParams containing the digest agorithm OID. Decode and return * a unified ECDSA/digest alg (e.g. CSSM_ALGID_SHA512WithECDSA). * Returns nonzero on error. */ int decodeECDSA_SigAlgParams( const CSSM_DATA *params, CSSM_ALGORITHMS *cssmAlg) /* RETURNED */ { SecAsn1CoderRef coder = NULL; if(SecAsn1CoderCreate(&coder)) { tpErrorLog("***Error in SecAsn1CoderCreate()\n"); return -1; } CSSM_X509_ALGORITHM_IDENTIFIER algParams; memset(&algParams, 0, sizeof(algParams)); int ourRtn = 0; bool algFound = false; if(SecAsn1DecodeData(coder, params, kSecAsn1AlgorithmIDTemplate, &algParams)) { tpErrorLog("***Error decoding CSSM_X509_ALGORITHM_IDENTIFIER\n"); ourRtn = -1; goto errOut; } CSSM_ALGORITHMS digestAlg; algFound = cssmOidToAlg(&algParams.algorithm, &digestAlg); if(!algFound) { tpErrorLog("***Unknown algorithm in CSSM_X509_ALGORITHM_IDENTIFIER\n"); ourRtn = -1; goto errOut; } switch(digestAlg) { case CSSM_ALGID_SHA1: *cssmAlg = CSSM_ALGID_SHA1WithECDSA; break; case CSSM_ALGID_SHA224: *cssmAlg = CSSM_ALGID_SHA224WithECDSA; break; case CSSM_ALGID_SHA256: *cssmAlg = CSSM_ALGID_SHA256WithECDSA; break; case CSSM_ALGID_SHA384: *cssmAlg = CSSM_ALGID_SHA384WithECDSA; break; case CSSM_ALGID_SHA512: *cssmAlg = CSSM_ALGID_SHA512WithECDSA; break; default: tpErrorLog("***Unknown algorithm in ECDSA_SigAlgParams\n"); ourRtn = -1; } errOut: SecAsn1CoderRelease(coder); return ourRtn; }
/* * 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; }
bool OCSPClientCertID::compareToExist( const CSSM_DATA &exist) { SecAsn1CoderRef coder; SecAsn1OCSPCertID certID; bool brtn = false; SecAsn1CoderCreate(&coder); memset(&certID, 0, sizeof(certID)); if(SecAsn1DecodeData(coder, &exist, kSecAsn1OCSPCertIDTemplate, &certID)) { goto errOut; } brtn = compareToExist(certID); errOut: SecAsn1CoderRelease(coder); return brtn; }
/* * Constructor, called by OCSPResponse. */ OCSPSingleResponse::OCSPSingleResponse( SecAsn1OCSPSingleResponse *resp) : mCertStatus(CS_NotParsed), mThisUpdate(NULL_TIME), mNextUpdate(NULL_TIME), mRevokedTime(NULL_TIME), mCrlReason(CrlReason_NONE), mExtensions(NULL) { assert(resp != NULL); SecAsn1CoderCreate(&mCoder); if((resp->certStatus.Data == NULL) || (resp->certStatus.Length == 0)) { ocspdErrorLog("OCSPSingleResponse: bad certStatus\n"); CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); } mCertStatus = (SecAsn1OCSPCertStatusTag)(resp->certStatus.Data[0] & SEC_ASN1_TAGNUM_MASK); if(mCertStatus == CS_Revoked) { /* decode further to get SecAsn1OCSPRevokedInfo */ SecAsn1OCSPCertStatus certStatus; memset(&certStatus, 0, sizeof(certStatus)); if(SecAsn1DecodeData(mCoder, &resp->certStatus, kSecAsn1OCSPCertStatusRevokedTemplate, &certStatus)) { ocspdErrorLog("OCSPSingleResponse: err decoding certStatus\n"); CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); } SecAsn1OCSPRevokedInfo *revokedInfo = certStatus.revokedInfo; if(revokedInfo != NULL) { /* Treat this as optional even for CS_Revoked */ mRevokedTime = genTimeToCFAbsTime(&revokedInfo->revocationTime); const CSSM_DATA *revReason = revokedInfo->revocationReason; if((revReason != NULL) && (revReason->Data != NULL) && (revReason->Length != 0)) { mCrlReason = revReason->Data[0]; } } } mThisUpdate = genTimeToCFAbsTime(&resp->thisUpdate); if(resp->nextUpdate != NULL) { mNextUpdate = genTimeToCFAbsTime(resp->nextUpdate); } mExtensions = new OCSPExtensions(resp->singleExtensions); ocspdDebug("OCSPSingleResponse: status %d reason %d", (int)mCertStatus, (int)mCrlReason); }
/* * Given an ECDSA public key in X509 format, extract the raw public key * bits in ECPOint format. */ OSStatus sslEcdsaPubKeyBits( CSSM_KEY_PTR pubKey, SSLBuffer *pubBits) /* data mallocd and RETURNED */ { SecAsn1CoderRef coder = NULL; CSSM_X509_SUBJECT_PUBLIC_KEY_INFO subjPubKeyInfo; OSStatus ortn = noErr; CSSM_KEYHEADER *hdr = &pubKey->KeyHeader; if(hdr->AlgorithmId != CSSM_ALGID_ECDSA) { sslErrorLog("sslEcdsaPubKeyBits: bad peer key algorithm\n"); return errSSLProtocol; } if(hdr->BlobType != CSSM_KEYBLOB_RAW) { /* No can do - this must be raw format, it came from the CL */ sslErrorLog("sslEcdsaPubKeyBits: bad peer key algorithm\n"); return errSSLProtocol; } if(hdr->Format != CSSM_KEYBLOB_RAW_FORMAT_X509) { sslErrorLog("sslEcdsaPubKeyBits: bad peer key format\n"); return errSSLProtocol; } /* KeyData is an encoded CSSM_X509_SUBJECT_PUBLIC_KEY_INFO */ ortn = SecAsn1CoderCreate(&coder); if(ortn) { return errSSLInternal; } /* subsequent errors to errOut: */ memset(&subjPubKeyInfo, 0, sizeof(subjPubKeyInfo)); ortn = SecAsn1DecodeData(coder, &pubKey->KeyData, kSecAsn1SubjectPublicKeyInfoTemplate, &subjPubKeyInfo); if(ortn) { printf("sslEcdsaPubKeyBits: error decoding public key\n"); goto errOut; } /* that key data is a BITSTRING */ ortn = SSLCopyBufferFromData(subjPubKeyInfo.subjectPublicKey.Data, subjPubKeyInfo.subjectPublicKey.Length >> 3, pubBits); errOut: SecAsn1CoderRelease(coder); return ortn; }
/* * Given a kerberos service tiocket in GSS form (i.e., an AP_REQ), * cook up a DER-encoded SPNEGO blob. Result is malloc'd; caller * must free. */ int spnegoCreateInit( const unsigned char *gssBlob, unsigned gssBlobLen, unsigned char **spnegoBlob, // mallocd and RETURNED unsigned *spnegoBlobLen) // RETURNED { SpnegoNegTokenInitGss negInit; SecAsn1CoderRef coder; if(SecAsn1CoderCreate(&coder)) { /* memory failure */ return -1; } memset(&negInit, 0, sizeof(negInit)); negInit.oid = CSSMOID_SPNEGO; negInit.token.mechTypeList = (CSSM_OID **)nssNullArray(coder, 2); negInit.token.mechTypeList[0] = (CSSM_OID *)&CSSMOID_KERB_V5_LEGACY; negInit.token.mechTypeList[1] = (CSSM_OID *)&CSSMOID_KERB_V5; /* no contextFlags for now, though we might need 'em */ CSSM_DATA gssData; if(gssBlob) { gssData.Data = (uint8 *)gssBlob; gssData.Length = gssBlobLen; negInit.token.mechToken = &gssData; } CSSM_DATA res = {0, NULL}; OSStatus ortn = SecAsn1EncodeItem(coder, &negInit, SpnegoNegTokenInitGssTemplate, &res); if(ortn) { SecAsn1CoderRelease(coder); return -1; } *spnegoBlob = (unsigned char *)malloc(res.Length); memmove(*spnegoBlob, res.Data, res.Length); *spnegoBlobLen = res.Length; /* this frees all memory allocated during SecAsn1EncodeItem() */ SecAsn1CoderRelease(coder); return 0; }
/* * 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; }
static OSStatus decodeDERUTF8String(const CSSM_DATA_PTR content, char *statusstr, size_t strsz) { // The statusString should use kSecAsn1SequenceOfUTF8StringTemplate, but doesn't OSStatus status = SECFailure; SecAsn1CoderRef coder = NULL; CSSM_DATA statusString; size_t len = 0; require(content && statusstr, xit); require_noerr(SecAsn1CoderCreate(&coder), xit); require_noerr(SecAsn1Decode(coder, content->Data, content->Length, kSecAsn1UTF8StringTemplate, &statusString), xit); status = 0; len = (statusString.Length < strsz)?(int)statusString.Length:strsz; if (statusstr && statusString.Data) strncpy(statusstr, (const char *)statusString.Data, len); xit: if (coder) SecAsn1CoderRelease(coder); return status; }
/* * DER encode in specified coder's memory. */ const CSSM_DATA *OCSPClientCertID::encode() { if(mEncoded.Data != NULL) { return &mEncoded; } SecAsn1OCSPCertID certID; uint8 issuerNameHash[CC_SHA1_DIGEST_LENGTH]; uint8 pubKeyHash[CC_SHA1_DIGEST_LENGTH]; /* algId refers to the hash we'll perform in issuer name and key */ certID.algId.algorithm = CSSMOID_SHA1; certID.algId.parameters.Data = nullParam; certID.algId.parameters.Length = sizeof(nullParam); /* SHA1(issuerName) */ ocspdSha1(mIssuerName.Data, (CC_LONG)mIssuerName.Length, issuerNameHash); /* SHA1(issuer public key bytes) */ ocspdSha1(mIssuerPubKey.Data, (CC_LONG)mIssuerPubKey.Length, pubKeyHash); /* build the CertID from those components */ certID.issuerNameHash.Data = issuerNameHash; certID.issuerNameHash.Length = CC_SHA1_DIGEST_LENGTH; certID.issuerPubKeyHash.Data = pubKeyHash; certID.issuerPubKeyHash.Length = CC_SHA1_DIGEST_LENGTH; certID.serialNumber = mSubjectSerial; /* encode */ SecAsn1CoderRef coder; SecAsn1CoderCreate(&coder); CSSM_DATA tmp = {0, NULL}; SecAsn1EncodeItem(coder, &certID, kSecAsn1OCSPCertIDTemplate, &tmp); allocCopyData(tmp, mEncoded); SecAsn1CoderRelease(coder); return &mEncoded; }
/* * 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 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; }
int main(int argc, char **argv) { CSSM_CL_HANDLE clHand; // CL handle CSSM_DATA rawCert = {0, NULL}; uint32 numFields; CSSM_HANDLE ResultsHandle = 0; char baseName[255]; char blobName[255]; char *cp; int rtn; int nameLen; CSSM_RETURN crtn; CSSM_DATA_PTR value; CSSM_KEY_PTR key; uint32 keySize; NSS_Certificate signedCert; SecAsn1CoderRef coder; if(argc != 2) { printf("usage: %s certFile\n", argv[0]); exit(1); } /* connect to CL */ clHand = clStartup(); if(clHand == 0) { printf("clStartup failure; aborting\n"); return 0; } /* subsequent errors to abort: */ /* read a in raw cert */ unsigned len; rtn = readFile(argv[1], &rawCert.Data, &len); if(rtn) { printf("Error %s reading file %s\n", strerror(rtn), argv[1]); exit(1); } rawCert.Length = len; /* C string of file name, terminating at '.' or space */ nameLen = strlen(argv[1]); memmove(baseName, argv[1], nameLen); baseName[nameLen] = '\0'; cp = strchr(baseName, '.'); if(cp) { *cp = '\0'; } cp = strchr(baseName, ' '); if(cp) { *cp = '\0'; } /* print filename and parsed subject name as comment */ crtn = CSSM_CL_CertGetFirstFieldValue( clHand, &rawCert, &CSSMOID_X509V1SubjectNameCStruct, &ResultsHandle, &numFields, &value); if(crtn) { printError("CSSM_CL_CertGetFirstFieldValue(CSSMOID_X509V1SubjectNameCStruct)", crtn); goto abort; } CSSM_CL_CertAbortQuery(clHand, ResultsHandle); if(value == NULL) { printf("Error extracting subject name\n"); goto abort; } printHeader(argv[1], value); CSSM_CL_FreeFieldValue(clHand, &CSSMOID_X509V1SubjectNameCStruct, value); /* print normalized & encoded subject name as C data */ crtn = CSSM_CL_CertGetFirstFieldValue( clHand, &rawCert, &SUBJECT_NAME_OID, &ResultsHandle, &numFields, &value); if(crtn) { printError("CSSM_CL_CertGetFirstFieldValue(CSSMOID_X509V1SubjectName)", crtn); goto abort; } CSSM_CL_CertAbortQuery(clHand, ResultsHandle); if(value == NULL) { printf("Error extracting subject name\n"); goto abort; } sprintf(blobName, "%s_subject", baseName); dumpDataBlob(blobName, value); #if WRITE_NAME_FILE writeFile(blobName, value->Data, (unsigned)value->Length); #endif CSSM_CL_FreeFieldValue(clHand, &SUBJECT_NAME_OID, value); /* print key blob as data */ crtn = CSSM_CL_CertGetFirstFieldValue( clHand, &rawCert, &CSSMOID_CSSMKeyStruct, &ResultsHandle, &numFields, &value); if(crtn) { printError("CSSM_CL_CertGetFirstFieldValue(CSSMOID_CSSMKeyStruct)", crtn); goto abort; } CSSM_CL_CertAbortQuery(clHand, ResultsHandle ); if(value == NULL) { printf("Error extracting public key\n"); goto abort; } if(value->Length != sizeof(CSSM_KEY)) { printf("CSSMOID_CSSMKeyStruct length error\n"); goto abort; } key = (CSSM_KEY_PTR)value->Data; sprintf(blobName, "%s_pubKey", baseName); dumpDataBlob(blobName, &key->KeyData); keySize = key->KeyHeader.LogicalKeySizeInBits; CSSM_CL_FreeFieldValue(clHand, &CSSMOID_CSSMKeyStruct, value); /* unnormalized DER-encoded issuer */ SecAsn1CoderCreate(&coder); memset(&signedCert, 0, sizeof(signedCert)); if(SecAsn1DecodeData(coder, &rawCert, kSecAsn1SignedCertTemplate, &signedCert)) { printf("***Error NSS-decoding certificate\n"); } else { sprintf(blobName, "%s_derIssuer", baseName); dumpDataBlob(blobName, &signedCert.tbs.derIssuer); } /* now the the struct containing all three */ printf("\n { &%s_subject, &%s_pubKey, %u },\n", baseName, baseName, (unsigned)keySize); abort: free(rawCert.Data); if(clHand != 0) { CSSM_ModuleDetach(clHand); } SecAsn1CoderRelease(coder); return 0; }
static int parseOcspResp( CSSM_CL_HANDLE clHand, unsigned char *inFile, unsigned inFileLen, bool verbose) { SecAsn1OCSPResponse topResp; SecAsn1CoderRef coder; OSStatus ortn; int indent = 0; const char *str; SecAsn1OCSPBasicResponse basicResp; unsigned numCerts = 0; SecAsn1CoderCreate(&coder); memset(&topResp, 0, sizeof(topResp)); ortn = SecAsn1Decode(coder, inFile, inFileLen, kSecAsn1OCSPResponseTemplate, &topResp); if(ortn) { printf("***Error decoding SecAsn1OCSPResponse\n"); goto errOut; } printf("OCSPResponse:\n"); indent += 2; doIndent(indent); printf("responseStatus: "); if(topResp.responseStatus.Length == 0) { printf("**MALFORMED**\n"); } else { switch(topResp.responseStatus.Data[0]) { case RS_Success: str = "RS_Success"; break; case RS_MalformedRequest: str = "RS_MalformedRequest"; break; case RS_InternalError: str = "RS_InternalError"; break; case RS_TryLater: str = "RS_TryLater"; break; case RS_Unused: str = "RS_Unused"; break; case RS_SigRequired: str = "RS_SigRequired"; break; case RS_Unauthorized: str = "RS_Unauthorized"; break; default: str = "MALFORMED (unknown enum)\n"; break; } printf("%s (%u(d))\n", str, topResp.responseStatus.Data[0]); } doIndent(indent); printf("ResponseBytes: "); if(topResp.responseBytes == NULL) { printf("empty\n"); goto errOut; } printf("\n"); indent += 2; doIndent(indent); printf("responseType: "); if(appCompareCssmData(&topResp.responseBytes->responseType, &CSSMOID_PKIX_OCSP_BASIC)) { str = "ocsp-basic"; } else { str = "Unknown type\n"; } printf("%s\n", str); /* decode the BasicOCSPResponse */ memset(&basicResp, 0, sizeof(basicResp)); ortn = SecAsn1DecodeData(coder, &topResp.responseBytes->response, kSecAsn1OCSPBasicResponseTemplate, &basicResp); if(ortn) { printf("***Error decoding BasicOCSPResponse\n"); goto errOut; } doIndent(indent); printf("BasicOCSPResponse:\n"); indent += 2; doIndent(indent); printf("ResponseData:\n"); parseResponseData(coder, indent + 2, basicResp.tbsResponseData); doIndent(indent); printf("sig: "); printDataAsHex(&basicResp.sig, 8); numCerts = ocspdArraySize((const void **)basicResp.certs); doIndent(indent); printf("Num Certs: %u\n", numCerts); if(verbose) { for(unsigned dex=0; dex<numCerts; dex++) { printf("+++++++++++++++++++++++++ Cert %u +++++++++++++++++++++++++\n", dex); printCert(basicResp.certs[dex]->Data, basicResp.certs[dex]->Length, CSSM_FALSE); printf("+++++++++++++++++++++++ End Cert %u +++++++++++++++++++++++\n", dex); } } indent -= 2; // end of BasicOCSPResponse indent -= 2; // end of ResponseBytes indent -= 2; // end of OCSPResponse errOut: SecAsn1CoderRelease(coder); return ortn; }
static int postOcspReq( CSSM_CL_HANDLE clHand, const unsigned char *certFile, unsigned certFileLen, const unsigned char *issuerCertFile, unsigned issuerCertFileLen, const char *responderURI, bool doParse, bool verbose, unsigned char **outFile, // RETURNED unsigned *outFileLen) // RETURNED { auto_ptr<CertParser> subject; auto_ptr<CertParser> issuer; CSSM_DATA uriData = {0, NULL}; CSSM_DATA *url = NULL; try { CSSM_DATA cdata = {certFileLen, (uint8 *)certFile}; subject.reset(new CertParser(clHand, cdata)); } catch(...) { printf("***Error parsing subject cert. Aborting.\n"); return -1; } try { CSSM_DATA cdata = {issuerCertFileLen, (uint8 *)issuerCertFile}; issuer.reset(new CertParser(clHand, cdata)); } catch(...) { printf("***Error parsing issuer cert. Aborting.\n"); return -1; } SecAsn1CoderRef coder; SecAsn1CoderCreate(&coder); /* subsequent errors to errOut: */ int ourRtn = 0; const CSSM_DATA *derReq = NULL; auto_ptr<OCSPRequest> ocspReq; if(responderURI != NULL) { uriData.Data = (uint8 *)responderURI; uriData.Length = strlen(responderURI); url = &uriData; } else { /* get OCSP URL from subject cert */ url = ocspUrlFromCert(*subject, coder); if(url == NULL) { printf("Sorry, no can do.\n"); ourRtn = -1; goto errOut; } } /* create DER-encoded OCSP request for subject */ try { ocspReq.reset(new OCSPRequest(*subject, *issuer, false)); derReq = ocspReq->encode(); } catch(...) { printf("***Error creating OCSP request. Aborting.\n"); ourRtn = -1; goto errOut; } /* do it */ CSSM_DATA ocspResp; CSSM_RETURN crtn; crtn = ocspdHttpPost(coder, *url, *derReq, ocspResp); if(crtn) { printf("***Error fetching OCSP response***\n"); cssmPerror("ocspdHttpPost", crtn); ourRtn = -1; goto errOut; } *outFile = ocspResp.Data; *outFileLen = ocspResp.Length; if(doParse) { parseOcspResp(clHand, ocspResp.Data, ocspResp.Length, verbose); } /* copy out */ *outFile = (unsigned char *)malloc(ocspResp.Length); *outFileLen = ocspResp.Length; memmove(*outFile, ocspResp.Data, ocspResp.Length); errOut: SecAsn1CoderRelease(coder); return ourRtn; }
static OSStatus validateTSAResponseAndAddTimeStamp(SecCmsSignerInfoRef signerinfo, CSSM_DATA_PTR tsaResponse, uint64_t expectedNonce) { OSStatus status = SECFailure; SecAsn1CoderRef coder = NULL; SecAsn1TimeStampRespDER respDER = {{{0}},}; SecAsn1TSAPKIStatusInfo *tsastatus = NULL; int respstatus = -1; int failinfo = -1; require_action(tsaResponse && tsaResponse->Data && tsaResponse->Length, xit, status = errSecTimestampMissing); require_noerr(SecAsn1CoderCreate(&coder), xit); require_noerr(SecTSAResponseCopyDEREncoding(coder, tsaResponse, &respDER), xit); #ifndef NDEBUG tsaWriteFileX("/tmp/tsa-timeStampToken.der", respDER.timeStampTokenDER.Data, respDER.timeStampTokenDER.Length); #endif tsastatus = (SecAsn1TSAPKIStatusInfo *)&respDER.status; require_action(tsastatus->status.Data, xit, status = errSecTimestampBadDataFormat); respstatus = (int)tsaDER_ToInt(&tsastatus->status); #ifndef NDEBUG char buf[80]={0,}; if (tsastatus->failInfo.Data) // e.g. FI_BadRequest failinfo = (int)tsaDER_ToInt(&tsastatus->failInfo); if (tsastatus->statusString.Data && tsastatus->statusString.Length) { OSStatus strrx = decodeDERUTF8String(&tsastatus->statusString, buf, sizeof(buf)); dprintf("decodeDERUTF8String status: %d\n", (int)strrx); } dprintf("validateTSAResponse: status: %d, failinfo: %d, %s\n", respstatus, failinfo, buf); #endif switch (respstatus) { case PKIS_Granted: case PKIS_GrantedWithMods: // Success status = noErr; break; case PKIS_Rejection: status = errSecTimestampRejection; break; case PKIS_Waiting: status = errSecTimestampWaiting; break; case PKIS_RevocationWarning: status = errSecTimestampRevocationWarning; break; case PKIS_RevocationNotification: status = errSecTimestampRevocationNotification; break; default: status = errSecTimestampSystemFailure; break; } require_noerr(status, xit); // If we succeeded, then we must have a TimeStampToken require_action(respDER.timeStampTokenDER.Data && respDER.timeStampTokenDER.Length, xit, status = errSecTimestampBadDataFormat); dprintf("timestamp full expected nonce: %lld\n", expectedNonce); /* The bytes in respDER are a full CMS message, which we need to check now for validity. The code for this is essentially the same code taht is done during a timestamp verify, except that we also need to check the nonce. */ require_noerr(status = decodeTimeStampToken(signerinfo, &respDER.timeStampTokenDER, NULL, expectedNonce), xit); status = SecCmsSignerInfoAddTimeStamp(signerinfo, &respDER.timeStampTokenDER); xit: if (coder) SecAsn1CoderRelease(coder); return status; }
/* * Finish encoding the message and obtain the encoded result. * Caller must CFRelease the result. */ OSStatus CMSEncoderCopyEncodedContent( CMSEncoderRef cmsEncoder, CFDataRef *encodedContent) { if((cmsEncoder == NULL) || (encodedContent == NULL)) { return errSecParam; } OSStatus ortn; switch(cmsEncoder->encState) { case ES_Updating: /* normal termination */ break; case ES_Final: /* already been called */ return errSecParam; case ES_Msg: case ES_Init: /* * The only time these are legal is when we're doing a SignedData * with certificates only (no signers, no content). */ if((cmsEncoder->signers != NULL) || (cmsEncoder->recipients != NULL) || (cmsEncoder->otherCerts == NULL)) { return errSecParam; } /* Set up for certs only */ ortn = cmsSetupForSignedData(cmsEncoder); if(ortn) { return ortn; } /* and an encoder */ ortn = cmsSetupEncoder(cmsEncoder); if(ortn) { return ortn; } break; } ASSERT(cmsEncoder->encoder != NULL); ortn = SecCmsEncoderFinish(cmsEncoder->encoder); /* regardless of the outcome, the encoder itself has been freed */ cmsEncoder->encoder = NULL; if(ortn) { return cmsRtnToOSStatus(ortn); } cmsEncoder->encState = ES_Final; if((cmsEncoder->encoderOut.Data == NULL) && !cmsEncoder->customCoder) { /* not sure how this could happen... */ dprintf("Successful encode, but no data\n"); return errSecInternalComponent; } if(cmsEncoder->customCoder) { /* we're done */ *encodedContent = NULL; return errSecSuccess; } /* in two out of three cases, we're done */ switch(cmsEncoder->op) { case EO_Sign: case EO_Encrypt: *encodedContent = CFDataCreate(NULL, (const UInt8 *)cmsEncoder->encoderOut.Data, cmsEncoder->encoderOut.Length); return errSecSuccess; case EO_SignEncrypt: /* proceed, more work to do */ break; } /* * Signing & encrypting. * Due to bugs in the libsecurity_smime encoder, it can't encode nested * ContentInfos in one shot. So we do another pass, specifying the SignedData * inside of the ContentInfo we just created as the data to encrypt. */ SecAsn1CoderRef asn1Coder = NULL; CSSM_DATA signedData = {0, NULL}; ortn = SecAsn1CoderCreate(&asn1Coder); if(ortn) { return ortn; } ortn = cmsContentInfoContent(asn1Coder, &cmsEncoder->encoderOut, &signedData); if(ortn) { goto errOut; } /* now just encrypt that, one-shot */ ortn = CMSEncode(NULL, /* no signers this time */ cmsEncoder->recipients, &CSSMOID_PKCS7_SignedData, /* fake out encoder so it doesn't try to actually * encode the signedData - this asserts the * SEC_OID_OTHER OID tag in the EnvelopedData's * ContentInfo */ FALSE, /* detachedContent */ kCMSAttrNone, /* signedAttributes - none this time */ signedData.Data, signedData.Length, encodedContent); errOut: if(asn1Coder) { SecAsn1CoderRelease(asn1Coder); } return ortn; }
/* * 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; }
/* * 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; }
OCSPResponse::OCSPResponse( const CSSM_DATA &resp, CFTimeInterval defaultTTL) // default time-to-live in seconds : mLatestNextUpdate(NULL_TIME), mExpireTime(NULL_TIME), mExtensions(NULL) { SecAsn1CoderCreate(&mCoder); memset(&mTopResp, 0, sizeof(mTopResp)); memset(&mBasicResponse, 0, sizeof(mBasicResponse)); memset(&mResponseData, 0, sizeof(mResponseData)); memset(&mResponderId, 0, sizeof(mResponderId)); mResponderIdTag = (SecAsn1OCSPResponderIDTag)0; // invalid mEncResponderName.Data = NULL; mEncResponderName.Length = 0; if(SecAsn1DecodeData(mCoder, &resp, kSecAsn1OCSPResponseTemplate, &mTopResp)) { ocspdErrorLog("OCSPResponse: decode failure at top level\n"); CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); } /* remainder is valid only on RS_Success */ if((mTopResp.responseStatus.Data == NULL) || (mTopResp.responseStatus.Length == 0)) { ocspdErrorLog("OCSPResponse: no responseStatus\n"); CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); } if(mTopResp.responseStatus.Data[0] != RS_Success) { /* not a failure of our constructor; this object is now useful, but * only for this one byte of status info */ return; } if(mTopResp.responseBytes == NULL) { /* I don't see how this can be legal on RS_Success */ ocspdErrorLog("OCSPResponse: empty responseBytes\n"); CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); } if(!ocspdCompareCssmData(&mTopResp.responseBytes->responseType, &CSSMOID_PKIX_OCSP_BASIC)) { ocspdErrorLog("OCSPResponse: unknown responseType\n"); CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); } /* decode the SecAsn1OCSPBasicResponse */ if(SecAsn1DecodeData(mCoder, &mTopResp.responseBytes->response, kSecAsn1OCSPBasicResponseTemplate, &mBasicResponse)) { ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPBasicResponse\n"); CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); } /* signature and cert evaluation done externally */ /* decode the SecAsn1OCSPResponseData */ if(SecAsn1DecodeData(mCoder, &mBasicResponse.tbsResponseData, kSecAsn1OCSPResponseDataTemplate, &mResponseData)) { ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPResponseData\n"); CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); } if(mResponseData.responderID.Data == NULL) { ocspdErrorLog("OCSPResponse: bad responderID\n"); CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); } /* choice processing for ResponderID */ mResponderIdTag = (SecAsn1OCSPResponderIDTag) (mResponseData.responderID.Data[0] & SEC_ASN1_TAGNUM_MASK); const SecAsn1Template *templ; switch(mResponderIdTag) { case RIT_Name: templ = kSecAsn1OCSPResponderIDAsNameTemplate; break; case RIT_Key: templ = kSecAsn1OCSPResponderIDAsKeyTemplate; break; default: ocspdErrorLog("OCSPResponse: bad responderID tag\n"); CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); } if(SecAsn1DecodeData(mCoder, &mResponseData.responderID, templ, &mResponderId)) { ocspdErrorLog("OCSPResponse: decode failure at responderID\n"); CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); } /* check temporal validity */ if(!calculateValidity(defaultTTL)) { /* Whoops, abort */ CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); } /* * Individual responses looked into when we're asked for a specific one * via singleResponse() */ mExtensions = new OCSPExtensions(mResponseData.responseExtensions); }
/* * 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; }