p12e.c

来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 2,255 行 · 第 1/4 页

C
2,255
字号
	    }	    /* initialize hmac */	    p12enc->hmacCx = HMAC_Create(				p12exp->integrityInfo.pwdInfo.algorithm,				key->data, key->len);	    SECITEM_ZfreeItem(key, PR_TRUE);	    if(!p12enc->hmacCx) {		PORT_SetError(SEC_ERROR_NO_MEMORY);		goto loser;	    }	    HMAC_Begin((HMACContext*)p12enc->hmacCx);	}    }    if(!p12enc->aSafeCinfo) {	goto loser;    }    return p12enc;loser:    if(p12enc) {	if(p12enc->aSafeCinfo) {	    SEC_PKCS7DestroyContentInfo(p12enc->aSafeCinfo);	}	PORT_Free(p12enc);    }    return NULL;}/* callback wrapper to allow the ASN1 engine to call the PKCS 12  * output routines. */static voidsec_pkcs12_encoder_out(void *arg, const char *buf, unsigned long len,		       int depth, SEC_ASN1EncodingPart data_kind){    struct sec_pkcs12_encoder_output *output;    output = (struct sec_pkcs12_encoder_output*)arg;    (* output->outputfn)(output->outputarg, buf, len);}/* callback wrapper to wrap SEC_PKCS7EncoderUpdate for ASN1 encoder */static void sec_pkcs12_wrap_pkcs7_encoder_update(void *arg, const char *buf, 				     unsigned long len, int depth, 				     SEC_ASN1EncodingPart data_kind){    SEC_PKCS7EncoderContext *ecx;    if(!buf || !len) {	return;    }    ecx = (SEC_PKCS7EncoderContext*)arg;    SEC_PKCS7EncoderUpdate(ecx, buf, len);}/* callback wrapper to wrap SEC_ASN1EncoderUpdate for PKCS 7 encoding */static voidsec_pkcs12_wrap_asn1_update_for_p7_update(void *arg, const char *buf,					  unsigned long len){    if(!buf && !len) return;    SEC_ASN1EncoderUpdate((SEC_ASN1EncoderContext*)arg, buf, len);}/* callback wrapper which updates the HMAC and passes on bytes to the  * appropriate output function. */static voidsec_pkcs12_asafe_update_hmac_and_encode_bits(void *arg, const char *buf,				      unsigned long len, int depth,				      SEC_ASN1EncodingPart data_kind){    sec_PKCS12EncoderContext *p12ecx;    p12ecx = (sec_PKCS12EncoderContext*)arg;    HMAC_Update((HMACContext*)p12ecx->hmacCx, (unsigned char *)buf, len);    sec_pkcs12_wrap_pkcs7_encoder_update(p12ecx->aSafeP7Ecx, buf, len,    					 depth, data_kind);}/* this function encodes content infos which are part of the * sequence of content infos labeled AuthenticatedSafes  */static SECStatus sec_pkcs12_encoder_asafe_process(sec_PKCS12EncoderContext *p12ecx){     SECStatus rv = SECSuccess;    SEC_PKCS5KeyAndPassword keyPwd;    SEC_PKCS7EncoderContext *p7ecx;    SEC_PKCS7ContentInfo *cinfo;    SEC_ASN1EncoderContext *ecx = NULL;    void *arg = NULL;    if(p12ecx->currentSafe < p12ecx->p12exp->authSafe.safeCount) {	SEC_PKCS12SafeInfo *safeInfo;	SECOidTag cinfoType;	safeInfo = p12ecx->p12exp->safeInfos[p12ecx->currentSafe];	/* skip empty safes */	if(safeInfo->itemCount == 0) {	    return SECSuccess;	}	cinfo = safeInfo->cinfo;	cinfoType = SEC_PKCS7ContentType(cinfo);	/* determine the safe type and set the appropriate argument */	switch(cinfoType) {	    case SEC_OID_PKCS7_DATA:		arg = NULL;		break;	    case SEC_OID_PKCS7_ENCRYPTED_DATA:		keyPwd.pwitem = &safeInfo->pwitem;		keyPwd.key = safeInfo->encryptionKey;		arg = &keyPwd;		break;	    case SEC_OID_PKCS7_ENVELOPED_DATA:		arg = NULL;		break;	    default:		return SECFailure;	}	/* start the PKCS7 encoder */	p7ecx = SEC_PKCS7EncoderStart(cinfo, 				      sec_pkcs12_wrap_asn1_update_for_p7_update,				      p12ecx->aSafeEcx, (PK11SymKey *)arg);	if(!p7ecx) {	    goto loser;	}	/* encode safe contents */	ecx = SEC_ASN1EncoderStart(safeInfo->safe, sec_PKCS12SafeContentsTemplate,				   sec_pkcs12_wrap_pkcs7_encoder_update, p7ecx);	if(!ecx) {	    goto loser;	}   	rv = SEC_ASN1EncoderUpdate(ecx, NULL, 0);	SEC_ASN1EncoderFinish(ecx);	ecx = NULL;	if(rv != SECSuccess) {	    goto loser;	}	/* finish up safe content info */	rv = SEC_PKCS7EncoderFinish(p7ecx, p12ecx->p12exp->pwfn, 				    p12ecx->p12exp->pwfnarg);    }    return SECSuccess;loser:    if(p7ecx) {	SEC_PKCS7EncoderFinish(p7ecx, p12ecx->p12exp->pwfn, 			       p12ecx->p12exp->pwfnarg);    }    if(ecx) {	SEC_ASN1EncoderFinish(ecx);    }    return SECFailure;}/* finish the HMAC and encode the macData so that it can be * encoded. */static SECStatussec_pkcs12_update_mac(sec_PKCS12EncoderContext *p12ecx){    SECItem hmac = { siBuffer, NULL, 0 };    SECStatus rv;    SGNDigestInfo *di = NULL;    void *dummy;    if(!p12ecx) {	return SECFailure;    }    /* make sure we are using password integrity mode */    if(!p12ecx->p12exp->integrityEnabled) {	return SECSuccess;    }    if(!p12ecx->p12exp->pwdIntegrity) {	return SECSuccess;    }    /* finish the hmac */    hmac.data = (unsigned char *)PORT_ZAlloc(SHA1_LENGTH);    if(!hmac.data) {	PORT_SetError(SEC_ERROR_NO_MEMORY);	return SECFailure;    }    rv = HMAC_Finish((HMACContext*)p12ecx->hmacCx,    		     hmac.data, &hmac.len, SHA1_LENGTH);    if(rv != SECSuccess) {	PORT_SetError(SEC_ERROR_NO_MEMORY);	goto loser;    }    /* create the digest info */    di = SGN_CreateDigestInfo(p12ecx->p12exp->integrityInfo.pwdInfo.algorithm,    			      hmac.data, hmac.len);    if(!di) {	PORT_SetError(SEC_ERROR_NO_MEMORY);	rv = SECFailure;	goto loser;    }    rv = SGN_CopyDigestInfo(p12ecx->arena, &p12ecx->mac.safeMac, di);    if(rv != SECSuccess) {	PORT_SetError(SEC_ERROR_NO_MEMORY);	goto loser;    }    /* encode the mac data */    dummy = SEC_ASN1EncodeItem(p12ecx->arena, &p12ecx->pfx.encodedMacData,     			    &p12ecx->mac, sec_PKCS12MacDataTemplate);    if(!dummy) {	PORT_SetError(SEC_ERROR_NO_MEMORY);	rv = SECFailure;    }loser:    if(di) {	SGN_DestroyDigestInfo(di);    }    if(hmac.data) {	SECITEM_ZfreeItem(&hmac, PR_FALSE);    }    HMAC_Destroy((HMACContext*)p12ecx->hmacCx);    p12ecx->hmacCx = NULL;    return rv;}/* wraps the ASN1 encoder update for PKCS 7 encoder */static voidsec_pkcs12_wrap_asn1_encoder_update(void *arg, const char *buf, 				    unsigned long len){    SEC_ASN1EncoderContext *cx;    cx = (SEC_ASN1EncoderContext*)arg;    SEC_ASN1EncoderUpdate(cx, buf, len);}/* pfx notify function for ASN1 encoder.  we want to stop encoding, once we reach * the authenticated safe.  at that point, the encoder will be updated via streaming * as the authenticated safe is  encoded.  */static voidsec_pkcs12_encoder_pfx_notify(void *arg, PRBool before, void *dest, int real_depth){    sec_PKCS12EncoderContext *p12ecx;    if(!before) {	return;    }    /* look for authenticated safe */    p12ecx = (sec_PKCS12EncoderContext*)arg;    if(dest != &p12ecx->pfx.encodedAuthSafe) {	return;    }    SEC_ASN1EncoderSetTakeFromBuf(p12ecx->ecx);    SEC_ASN1EncoderSetStreaming(p12ecx->ecx);    SEC_ASN1EncoderClearNotifyProc(p12ecx->ecx);}/* SEC_PKCS12Encode *	Encodes the PFX item and returns it to the output function, via *	callback.  the output function must be capable of multiple updates. *	 *	p12exp - the export context  *	output - the output function callback, will be called more than once, *		 must be able to accept streaming data. *	outputarg - argument for the output callback. */SECStatusSEC_PKCS12Encode(SEC_PKCS12ExportContext *p12exp, 		 SEC_PKCS12EncoderOutputCallback output, void *outputarg){    sec_PKCS12EncoderContext *p12enc;    struct sec_pkcs12_encoder_output outInfo;    SECStatus rv;    if(!p12exp || !output) {	return SECFailure;    }    /* get the encoder context */    p12enc = sec_pkcs12_encoder_start_context(p12exp);    if(!p12enc) {	return SECFailure;    }    outInfo.outputfn = output;    outInfo.outputarg = outputarg;    /* set up PFX encoder.  Set it for streaming */    p12enc->ecx = SEC_ASN1EncoderStart(&p12enc->pfx, sec_PKCS12PFXItemTemplate,				       sec_pkcs12_encoder_out, 				       &outInfo);    if(!p12enc->ecx) {	PORT_SetError(SEC_ERROR_NO_MEMORY);	rv = SECFailure;	goto loser;    }    SEC_ASN1EncoderSetStreaming(p12enc->ecx);    SEC_ASN1EncoderSetNotifyProc(p12enc->ecx, sec_pkcs12_encoder_pfx_notify, p12enc);    rv = SEC_ASN1EncoderUpdate(p12enc->ecx, NULL, 0);    if(rv != SECSuccess) {	rv = SECFailure;	goto loser;    }    /* set up asafe cinfo - the output of the encoder feeds the PFX encoder */    p12enc->aSafeP7Ecx = SEC_PKCS7EncoderStart(p12enc->aSafeCinfo,     					       sec_pkcs12_wrap_asn1_encoder_update,    					       p12enc->ecx, NULL);    if(!p12enc->aSafeP7Ecx) {	rv = SECFailure;	goto loser;    }    /* encode asafe */    if(p12enc->p12exp->integrityEnabled && p12enc->p12exp->pwdIntegrity) {	p12enc->aSafeEcx = SEC_ASN1EncoderStart(&p12enc->p12exp->authSafe,					sec_PKCS12AuthenticatedSafeTemplate, 					sec_pkcs12_asafe_update_hmac_and_encode_bits,    					p12enc);    } else {	p12enc->aSafeEcx = SEC_ASN1EncoderStart(&p12enc->p12exp->authSafe,				sec_PKCS12AuthenticatedSafeTemplate,				sec_pkcs12_wrap_pkcs7_encoder_update,				p12enc->aSafeP7Ecx);    }    if(!p12enc->aSafeEcx) {	rv = SECFailure;	goto loser;    }    SEC_ASN1EncoderSetStreaming(p12enc->aSafeEcx);    SEC_ASN1EncoderSetTakeFromBuf(p12enc->aSafeEcx); 	    /* encode each of the safes */			     while(p12enc->currentSafe != p12enc->p12exp->safeInfoCount) {	sec_pkcs12_encoder_asafe_process(p12enc);	p12enc->currentSafe++;    }    SEC_ASN1EncoderClearTakeFromBuf(p12enc->aSafeEcx);    SEC_ASN1EncoderClearStreaming(p12enc->aSafeEcx);    SEC_ASN1EncoderUpdate(p12enc->aSafeEcx, NULL, 0);    SEC_ASN1EncoderFinish(p12enc->aSafeEcx);    /* finish the encoding of the authenticated safes */    rv = SEC_PKCS7EncoderFinish(p12enc->aSafeP7Ecx, p12exp->pwfn,     				p12exp->pwfnarg);    if(rv != SECSuccess) {	goto loser;    }    SEC_ASN1EncoderClearTakeFromBuf(p12enc->ecx);    SEC_ASN1EncoderClearStreaming(p12enc->ecx);    /* update the mac, if necessary */    rv = sec_pkcs12_update_mac(p12enc);    if(rv != SECSuccess) {	goto loser;    }       /* finish encoding the pfx */     rv = SEC_ASN1EncoderUpdate(p12enc->ecx, NULL, 0);    SEC_ASN1EncoderFinish(p12enc->ecx);loser:    return rv;}voidSEC_PKCS12DestroyExportContext(SEC_PKCS12ExportContext *p12ecx){    int i = 0;    if(!p12ecx) {	return;    }    if(p12ecx->safeInfos) {	i = 0;	while(p12ecx->safeInfos[i] != NULL) {	    if(p12ecx->safeInfos[i]->encryptionKey) {		PK11_FreeSymKey(p12ecx->safeInfos[i]->encryptionKey);	    }	    if(p12ecx->safeInfos[i]->cinfo) {		SEC_PKCS7DestroyContentInfo(p12ecx->safeInfos[i]->cinfo);	    }	    i++;	}    }    PORT_FreeArena(p12ecx->arena, PR_TRUE);}/********************************* * All-in-one routines for exporting certificates  *********************************/struct inPlaceEncodeInfo {    PRBool error;    SECItem outItem;};static void sec_pkcs12_in_place_encoder_output(void *arg, const char *buf, unsigned long len){    struct inPlaceEncodeInfo *outInfo = (struct inPlaceEncodeInfo*)arg;    if(!outInfo || !len || outInfo->error) {	return;    }    if(!outInfo->outItem.data) {	outInfo->outItem.data = (unsigned char*)PORT_ZAlloc(len);	outInfo->outItem.len = 0;    } else {	if(!PORT_Realloc(&(outInfo->outItem.data), (outInfo->outItem.len + len))) {	    SECITEM_ZfreeItem(&(outInfo->outItem), PR_FALSE);	    outInfo->outItem.data = NULL;	    PORT_SetError(SEC_ERROR_NO_MEMORY);	    outInfo->error = PR_TRUE;	    return;	}    }    PORT_Memcpy(&(outInfo->outItem.data[outInfo->outItem.len]), buf, len);    outInfo->outItem.len += len;    return;}/* * SEC_PKCS12ExportCertifcateAndKeyUsingPassword *	Exports a certificate/key pair using password-based encryption and *	authentication. * * pwfn, pwfnarg - password function and argument for the key database * cert - the certificate to export * certDb - certificate database * pwitem - the password to use * shroudKey - encrypt the key externally,  * keyShroudAlg - encryption algorithm for key * encryptionAlg - the algorithm with which data is encrypted * integrityAlg - the algorithm for integrity */SECItem *SEC_PKCS12ExportCertificateAndKeyUsingPassword(				SECKEYGetPasswordKey pwfn, void *pwfnarg,				CERTCertificate *cert, PK11SlotInfo *slot,				CERTCertDBHandle *certDb, SECItem *pwitem,				PRBool shroudKey, SECOidTag shroudAlg,				PRBool encryptCert, SECOidTag certEncAlg,				SECOidTag integrityAlg, void *wincx){    struct inPlaceEncodeInfo outInfo;    SEC_PKCS12ExportContext *p12ecx = NULL;    SEC_PKCS12SafeInfo *keySafe, *certSafe;    SECItem *returnItem = NULL;    if(!cert || !pwitem || !slot) {	return NULL;    }    outInfo.error = PR_FALSE;    outInfo.outItem.data = NULL;    outInfo.outItem.len = 0;    p12ecx = SEC_PKCS12CreateExportContext(pwfn, pwfnarg, slot, wincx);    if(!p12ecx) {	return NULL;    }    /* set up cert safe */    if(encryptCert) {	certSafe = SEC_PKCS12CreatePasswordPrivSafe(p12ecx, pwitem, certEncAlg);    } else {	certSafe = SEC_PKCS12CreateUnencryptedSafe(p12ecx);    }    if(!certSafe) {	goto loser;    }    /* set up key safe */    if(shroudKey) {	keySafe = SEC_PKCS12CreateUnencryptedSafe(p12ecx);    } else {	keySafe = certSafe;    }    if(!keySafe) {	goto loser;    }    /* add integrity mode */    if(SEC_PKCS12AddPasswordIntegrity(p12ecx, pwitem, integrityAlg) 		!= SECSuccess) {	goto loser;    }    /* add cert and key pair */    if(SEC_PKCS12AddCertAndKey(p12ecx, certSafe, NULL, cert, certDb, 			       keySafe, NULL, shroudKey, pwitem, shroudAlg)		!= SECSuccess) {	goto loser;    }    /* encode the puppy */    if(SEC_PKCS12Encode(p12ecx, sec_pkcs12_in_place_encoder_output, &outInfo)		!= SECSuccess) {	goto loser;    }    if(outInfo.error) {	goto loser;    }    SEC_PKCS12DestroyExportContext(p12ecx);	    returnItem = SECITEM_DupItem(&outInfo.outItem);    SECITEM_ZfreeItem(&outInfo.outItem, PR_FALSE);    return returnItem;loser:    if(outInfo.outItem.data) {	SECITEM_ZfreeItem(&(outInfo.outItem), PR_TRUE);    }    if(p12ecx) {	SEC_PKCS12DestroyExportContext(p12ecx);    }    return NULL;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?