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; }
/* * 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]); } } }
/* * 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; }
/* * 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; }
/* * Obtain the content of a contentInfo, This basically strips off the contentType OID * and returns its ASN_ANY content, allocated the provided coder's memory space. */ static OSStatus cmsContentInfoContent( SecAsn1CoderRef asn1Coder, const CSSM_DATA *contentInfo, CSSM_DATA *content) /* RETURNED */ { OSStatus ortn; SimpleContentInfo decodedInfo; memset(&decodedInfo, 0, sizeof(decodedInfo)); ortn = SecAsn1DecodeData(asn1Coder, contentInfo, cmsSimpleContentInfoTemplate, &decodedInfo); if(ortn) { return ortn; } if(decodedInfo.content.Data == NULL) { dprintf("***Error decoding contentInfo: no content\n"); return errSecInternalComponent; } *content = decodedInfo.content; return errSecSuccess; }
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; }
/* * 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; }
/* * 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; }
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; }
/* decode and parse tbsResponseData, sitting in SecAsn1OCSPBasicResponse as an * ASN_ANY */ static int parseResponseData( SecAsn1CoderRef coder, int indent, const CSSM_DATA &tbsResponseData) { SecAsn1OCSPResponseData respData; SecAsn1OCSPResponderID responderID; uint8 tag; const SecAsn1Template *templ; unsigned numExts; memset(&respData, 0, sizeof(respData)); OSStatus ortn = SecAsn1DecodeData(coder, &tbsResponseData, kSecAsn1OCSPResponseDataTemplate, &respData); if(ortn) { printf("***Error decoding ResponseData\n"); return 1; } if(respData.version && respData.version->Data) { doIndent(indent); printf("version: %u\n", respData.version->Data[0]); } doIndent(indent); printf("ResponderID:\n"); indent += 2; memset(&responderID, 0, sizeof(responderID)); if(respData.responderID.Data == NULL) { doIndent(indent); printf("***Malformed(empty)***\n"); return 1; } /* lame-o choice processing */ tag = respData.responderID.Data[0] & SEC_ASN1_TAGNUM_MASK; switch(tag) { case RIT_Name: templ = kSecAsn1OCSPResponderIDAsNameTemplate; break; case RIT_Key: templ = kSecAsn1OCSPResponderIDAsKeyTemplate; break; default: doIndent(indent); printf("**Unknown tag for ResponderID (%u)\n", tag); return 1; } ortn = SecAsn1DecodeData(coder, &respData.responderID, templ, &responderID); if(ortn) { doIndent(indent); printf("***Error decoding ResponderID\n"); return 1; } doIndent(indent); switch(tag) { case RIT_Name: printf("byName:\n"); printName((NSS_Name &)responderID.byName, indent + 2); break; case RIT_Key: printf("byKey : "); printDataAsHex(&responderID.byKey); break; } indent -= 2; // end of ResponderID doIndent(indent); printf("producedAt: "); printString(&respData.producedAt); unsigned numResps = ocspdArraySize((const void **)respData.responses); doIndent(indent); printf("Num responses: %u\n", numResps); for(unsigned dex=0; dex<numResps; dex++) { SecAsn1OCSPSingleResponse *resp = respData.responses[dex]; doIndent(indent); printf("Response %u:\n", dex); indent += 2; doIndent(indent); printf("CertID:\n"); dumpCertID(&resp->certID, indent + 2); doIndent(indent); printf("certStatus: "); /* lame-o choice processing */ tag = resp->certStatus.Data[0] & SEC_ASN1_TAGNUM_MASK; switch(tag) { case CS_Good: printf("Good\n"); break; case CS_Unknown: printf("Unknown\n"); break; default: printf("**MALFORMED cert status tag (%u)\n", tag); break; case CS_Revoked: { printf("Revoked\n"); doIndent(indent); SecAsn1OCSPCertStatus certStatus; memset(&certStatus, 0, sizeof(certStatus)); ortn = SecAsn1DecodeData(coder, &resp->certStatus, kSecAsn1OCSPCertStatusRevokedTemplate, &certStatus); if(ortn) { doIndent(indent); printf("***error parsing RevokedInfo\n"); break; } if(certStatus.revokedInfo == NULL) { doIndent(indent); printf("***GAK! Malformed (empty) revokedInfo\n");break; } printf("RevokedIndfo:\n"); indent += 2; doIndent(indent); printf("revocationTime: "); printString(&certStatus.revokedInfo->revocationTime); if(certStatus.revokedInfo->revocationReason) { doIndent(indent); printf("reason: %u\n", certStatus.revokedInfo->revocationReason->Data[0]); } indent -= 2; // end of RevokedInfo break; } } /* switch cert status tag */ doIndent(indent); printf("thisUpdate: "); printString(&resp->thisUpdate); if(resp->nextUpdate) { doIndent(indent); printf("nextUpdate: "); printString(resp->nextUpdate); } numExts = ocspdArraySize((const void **)resp->singleExtensions); for(unsigned extDex=0; extDex<numExts; extDex++) { doIndent(indent); printf("singleExtensions[%u]\n", extDex); printOcspExt(coder, resp->singleExtensions[extDex], indent + 2); } indent -= 2; // end of resp[dex] } numExts = ocspdArraySize((const void **)respData.responseExtensions); for(unsigned extDex=0; extDex<numExts; extDex++) { doIndent(indent); printf("responseExtensions[%u]\n", extDex); printOcspExt(coder, respData.responseExtensions[extDex], indent + 2); } return 0; }
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); }
/* * Given an ECDSA key in CSSM format, extract the SSL_ECDSA_NamedCurve * from its algorithm parameters. */ OSStatus sslEcdsaPeerCurve( CSSM_KEY_PTR pubKey, SSL_ECDSA_NamedCurve *namedCurve) { SecAsn1CoderRef coder = NULL; CSSM_X509_SUBJECT_PUBLIC_KEY_INFO subjPubKeyInfo; CSSM_X509_ALGORITHM_IDENTIFIER *algId = &subjPubKeyInfo.algorithm; CSSM_OID curveOid; OSStatus ortn; CSSM_KEYHEADER *hdr = &pubKey->KeyHeader; if(hdr->AlgorithmId != CSSM_ALGID_ECDSA) { sslErrorLog("sslEcdsaPeerCurve: 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("sslEcdsaPeerCurve: bad peer key algorithm\n"); return errSSLProtocol; } if(hdr->Format != CSSM_KEYBLOB_RAW_FORMAT_X509) { sslErrorLog("sslEcdsaPeerCurve: 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("sslEcdsaPeerCurve: error decoding public key\n"); goto errOut; } if(!nssCompareCssmData(&algId->algorithm, &CSSMOID_ecPublicKey)) { printf("sslEcdsaPeerCurve: unexpected algorithm ID in public key\n"); ortn = errSSLProtocol; goto errOut; } if((algId->parameters.Data[0] != BER_TAG_OID) || (algId->parameters.Length < 2)) { printf("sslEcdsaPeerCurve: missing algorithm parameters in public key\n"); ortn = errSSLProtocol; goto errOut; } /* * The curve OID is DER-encoded since the parameters are ASN_ANY. * Quickie decode for further processing... */ curveOid.Data = algId->parameters.Data + 2; curveOid.Length = algId->parameters.Length - 2; /* algId->parameters is the curve OID */ if(nssCompareCssmData(&curveOid, &CSSMOID_secp256r1)) { *namedCurve = SSL_Curve_secp256r1; } else if(nssCompareCssmData(&curveOid, &CSSMOID_secp384r1)) { *namedCurve = SSL_Curve_secp384r1; } else if(nssCompareCssmData(&curveOid, &CSSMOID_secp521r1)) { *namedCurve = SSL_Curve_secp521r1; } /* Others? Later. That's all we support for now. */ else { printf("sslEcdsaPeerCurve: missing algorithm parameters in public key\n"); ortn = errSSLProtocol; } errOut: SecAsn1CoderRelease(coder); return ortn; }