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);
}
Beispiel #9
0
/*
 * 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;
}
Beispiel #16
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);
}
Beispiel #17
0
/*
 * 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;
}