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 + -
显示快捷键?