예제 #1
0
/*
 * 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;
}
예제 #2
0
/*
 * 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]);
	}
    }
}
예제 #4
0
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;
}
예제 #6
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);
	}
}
예제 #8
0
/*
 * 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;
}
예제 #10
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;
}
예제 #12
0
/*
 * 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;
}
예제 #13
0
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;
}
예제 #14
0
/*
 * 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);
}
예제 #15
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;
}
예제 #16
0
/*
 * 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;
}
예제 #17
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;
}
예제 #18
0
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;
}
예제 #19
0
/*
 * 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;
}
예제 #20
0
/*
 * 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;
}
예제 #21
0
/*
 * 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;
}
예제 #25
0
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;
}
예제 #26
0
/*
 * 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;
}
예제 #27
0
/*
 * 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;
}
예제 #28
0
/*
 * 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;
}
예제 #29
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);
}
예제 #30
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;
}