p12d.c
来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 2,435 行 · 第 1/5 页
C
2,435 行
p12dcx->errorValue = SEC_ERROR_PKCS12_UNSUPPORTED_VERSION; goto loser; } /* start the decode of the aSafes cinfo... */ rv = sec_pkcs12_decode_start_asafes_cinfo(p12dcx); if(rv != SECSuccess) { goto loser; } /* set the filter proc to update the authenticated safes. */ SEC_ASN1DecoderSetFilterProc(p12dcx->pfxDcx, sec_pkcs12_decode_asafes_cinfo_update, p12dcx, PR_TRUE); } if(!before && (dest == &p12dcx->pfx.encodedAuthSafe)) { /* we are done decoding the authenticatedSafes, so we need to * finish the decoderContext and clear the filter proc * and close the hmac callback, if present */ p12dcx->aSafeCinfo = SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx); p12dcx->aSafeP7Dcx = NULL; if(!p12dcx->aSafeCinfo) { p12dcx->errorValue = PORT_GetError(); goto loser; } SEC_ASN1DecoderClearFilterProc(p12dcx->pfxDcx); if(p12dcx->dClose && ((*p12dcx->dClose)(p12dcx->dArg, PR_FALSE) != SECSuccess)) { p12dcx->errorValue = PORT_GetError(); goto loser; } } return;loser: p12dcx->error = PR_TRUE;}/* SEC_PKCS12DecoderStart * Creates a decoder context for decoding a PKCS 12 PDU objct. * This function sets up the initial decoding context for the * PFX and sets the needed state variables. * * pwitem - the password for the hMac and any encoded safes. * this should be changed to take a callback which retrieves * the password. it may be possible for different safes to * have different passwords. also, the password is already * in unicode. it should probably be converted down below via * a unicode conversion callback. * slot - the slot to import the dataa into should multiple slots * be supported based on key type and cert type? * dOpen, dClose, dRead, dWrite - digest routines for writing data * to a file so it could be read back and the hmack recomputed * and verified. doesn't seem to be away for both encoding * and decoding to be single pass, thus the need for these * routines. * dArg - the argument for dOpen, etc. * * This function returns the decoder context, if it was successful. * Otherwise, null is returned. */SEC_PKCS12DecoderContext *SEC_PKCS12DecoderStart(SECItem *pwitem, PK11SlotInfo *slot, void *wincx, digestOpenFn dOpen, digestCloseFn dClose, digestIOFn dRead, digestIOFn dWrite, void *dArg){ SEC_PKCS12DecoderContext *p12dcx; PRArenaPool *arena; arena = PORT_NewArena(2048); /* different size? */ if(!arena) { PORT_SetError(SEC_ERROR_NO_MEMORY); return NULL; } /* allocate the decoder context and set the state variables */ p12dcx = (SEC_PKCS12DecoderContext*)PORT_ArenaZAlloc(arena, sizeof(SEC_PKCS12DecoderContext)); if(!p12dcx) { PORT_SetError(SEC_ERROR_NO_MEMORY); goto loser; } p12dcx->arena = arena; p12dcx->pwitem = pwitem; p12dcx->slot = (slot ? slot : PK11_GetInternalKeySlot()); p12dcx->wincx = wincx;#ifdef IS_LITTLE_ENDIAN p12dcx->swapUnicodeBytes = PR_TRUE;#else p12dcx->swapUnicodeBytes = PR_FALSE;#endif p12dcx->errorValue = 0; p12dcx->error = PR_FALSE; /* a slot is *required */ if(!slot) { PORT_SetError(SEC_ERROR_NO_MEMORY); goto loser; } /* start the decoding of the PFX and set the notify proc * for the PFX item. */ p12dcx->pfxDcx = SEC_ASN1DecoderStart(p12dcx->arena, &p12dcx->pfx, sec_PKCS12PFXItemTemplate); if(!p12dcx->pfxDcx) { PORT_SetError(SEC_ERROR_NO_MEMORY); goto loser; } SEC_ASN1DecoderSetNotifyProc(p12dcx->pfxDcx, sec_pkcs12_decoder_pfx_notify_proc, p12dcx); /* set up digest functions */ p12dcx->dOpen = dOpen; p12dcx->dWrite = dWrite; p12dcx->dClose = dClose; p12dcx->dRead = dRead; p12dcx->dArg = dArg; return p12dcx;loser: PORT_FreeArena(arena, PR_TRUE); return NULL;}/* SEC_PKCS12DecoderUpdate * Streaming update sending more data to the decoder. If * an error occurs, SECFailure is returned. * * p12dcx - the decoder context * data, len - the data buffer and length of data to send to * the update functions. */SECStatusSEC_PKCS12DecoderUpdate(SEC_PKCS12DecoderContext *p12dcx, unsigned char *data, unsigned long len){ SECStatus rv; if(!p12dcx || p12dcx->error) { return SECFailure; } /* update the PFX decoder context */ rv = SEC_ASN1DecoderUpdate(p12dcx->pfxDcx, (const char *)data, len); if(rv != SECSuccess) { p12dcx->errorValue = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE; goto loser; } return SECSuccess;loser: p12dcx->error = PR_TRUE; return SECFailure;}/* IN_BUF_LEN should be larger than SHA1_LENGTH */#define IN_BUF_LEN 80/* verify the hmac by reading the data from the temporary file * using the routines specified when the decodingContext was * created and return SECSuccess if the hmac matches. */static SECStatussec_pkcs12_decoder_verify_mac(SEC_PKCS12DecoderContext *p12dcx){ SECStatus rv = SECFailure; PBEBitGenContext *pbeCtxt = NULL; SECItem *hmacKey = NULL, hmacRes; unsigned char buf[IN_BUF_LEN]; void *hmacCx; unsigned int bufLen; int iteration; if(!p12dcx || p12dcx->error) { return SECFailure; } /* generate hmac key */ if(p12dcx->macData.iter.data) { iteration = (int)DER_GetInteger(&p12dcx->macData.iter); } else { iteration = 1; } pbeCtxt = PBE_CreateContext(SECOID_GetAlgorithmTag( &p12dcx->macData.safeMac.digestAlgorithm), pbeBitGenIntegrityKey, p12dcx->pwitem, &p12dcx->macData.macSalt, 160, iteration); if(!pbeCtxt) { return SECFailure; } hmacKey = PBE_GenerateBits(pbeCtxt); PBE_DestroyContext(pbeCtxt); pbeCtxt = NULL; if(!hmacKey) { return SECFailure; } /* init hmac */ hmacCx = HMAC_Create(SECOID_GetAlgorithmTag( &p12dcx->macData.safeMac.digestAlgorithm), hmacKey->data, hmacKey->len); SECITEM_ZfreeItem(hmacKey, PR_TRUE); hmacKey = NULL; if(!hmacCx) { PORT_SetError(SEC_ERROR_NO_MEMORY); return SECFailure; } HMAC_Begin((HMACContext*)hmacCx); /* try to open the data for readback */ if(p12dcx->dOpen && ((*p12dcx->dOpen)(p12dcx->dArg, PR_TRUE) != SECSuccess)) { goto loser; } /* read the data back IN_BUF_LEN bytes at a time and recompute * the hmac. if fewer bytes are read than are requested, it is * assumed that the end of file has been reached. if bytesRead * is returned as -1, then an error occured reading from the * file. */ while(1) { int bytesRead = (*p12dcx->dRead)(p12dcx->dArg, buf, IN_BUF_LEN); if(bytesRead == -1) { goto loser; } HMAC_Update((HMACContext*)hmacCx, buf, bytesRead); if(bytesRead < IN_BUF_LEN) { break; } } /* finish the hmac context */ HMAC_Finish((HMACContext*)hmacCx, buf, &bufLen, IN_BUF_LEN); HMAC_Destroy((HMACContext*)hmacCx); hmacCx = NULL; hmacRes.data = buf; hmacRes.len = bufLen; /* is the hmac computed the same as the hmac which was decoded? */ rv = SECSuccess; if(SECITEM_CompareItem(&hmacRes, &p12dcx->macData.safeMac.digest) != SECEqual) { PORT_SetError(SEC_ERROR_PKCS12_INVALID_MAC); rv = SECFailure; }loser: /* close the file and remove it */ if(p12dcx->dClose) { (*p12dcx->dClose)(p12dcx->dArg, PR_TRUE); } if(hmacCx) { HMAC_Destroy((HMACContext*)hmacCx); } if(hmacKey) { SECITEM_ZfreeItem(hmacKey, PR_TRUE); } return rv;}/* SEC_PKCS12DecoderVerify * Verify the macData or the signature of the decoded PKCS 12 PDU. * If the signature or the macData do not match, SECFailure is * returned. * * p12dcx - the decoder context */SECStatusSEC_PKCS12DecoderVerify(SEC_PKCS12DecoderContext *p12dcx){ SECStatus rv = SECSuccess; /* make sure that no errors have occured... */ if(!p12dcx || p12dcx->error) { return SECFailure; } /* check the signature or the mac depending on the type of * integrity used. */ if(p12dcx->pfx.encodedMacData.len) { rv = SEC_ASN1DecodeItem(p12dcx->arena, &p12dcx->macData, sec_PKCS12MacDataTemplate, &p12dcx->pfx.encodedMacData); if(rv == SECSuccess) { return sec_pkcs12_decoder_verify_mac(p12dcx); } else { PORT_SetError(SEC_ERROR_NO_MEMORY); } } else { if(SEC_PKCS7VerifySignature(p12dcx->aSafeCinfo, certUsageEmailSigner, PR_FALSE)) { return SECSuccess; } else { PORT_SetError(SEC_ERROR_PKCS12_INVALID_MAC); } } return SECFailure;}/* SEC_PKCS12DecoderFinish * Free any open ASN1 or PKCS7 decoder contexts and then * free the arena pool which everything should be allocated * from. This function should be called upon completion of * decoding and installing of a pfx pdu. This should be * called even if an error occurs. * * p12dcx - the decoder context */voidSEC_PKCS12DecoderFinish(SEC_PKCS12DecoderContext *p12dcx){ void *freedCtxt = NULL; if(!p12dcx) { return; } if(p12dcx->pfxDcx) { SEC_ASN1DecoderFinish(p12dcx->pfxDcx); p12dcx->pfxDcx = NULL; } if(p12dcx->aSafeDcx) { SEC_ASN1DecoderFinish(p12dcx->aSafeDcx); p12dcx->aSafeDcx = NULL; } if(p12dcx->currentASafeP7Dcx) { SEC_PKCS7DecoderFinish(p12dcx->currentASafeP7Dcx); p12dcx->currentASafeP7Dcx = NULL; } if(p12dcx->aSafeP7Dcx) { SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx); } if(p12dcx->hmacDcx) { SEC_ASN1DecoderFinish(p12dcx->hmacDcx); p12dcx->hmacDcx = NULL; } if(p12dcx->arena) { PORT_FreeArena(p12dcx->arena, PR_TRUE); }}static SECStatussec_pkcs12_decoder_set_attribute_value(sec_PKCS12SafeBag *bag, SECOidTag attributeType, SECItem *attrValue){ int i = 0; SECOidData *oid; if(!bag || !attrValue) { return SECFailure; } oid = SECOID_FindOIDByTag(attributeType); if(!oid) { PORT_SetError(SEC_ERROR_NO_MEMORY); return SECFailure; } if(!bag->attribs) { bag->attribs = (sec_PKCS12Attribute**)PORT_ArenaZAlloc(bag->arena, sizeof(sec_PKCS12Attribute *) * 2); } else { while(bag->attribs[i]) i++; bag->attribs = (sec_PKCS12Attribute **)PORT_ArenaGrow(bag->arena, bag->attribs, (i + 1) * sizeof(sec_PKCS12Attribute *), (i + 2) * sizeof(sec_PKCS12Attribute *)); } if(!bag->attribs) { PORT_SetError(SEC_ERROR_NO_MEMORY); return SECFailure; } bag->attribs[i] = (sec_PKCS12Attribute*)PORT_ArenaZAlloc(bag->arena, sizeof(sec_PKCS12Attribute)); if(!bag->attribs) { PORT_SetError(SEC_ERROR_NO_MEMORY); return SECFailure; } bag->attribs[i]->attrValue = (SECItem**)PORT_ArenaZAlloc(bag->arena, sizeof(SECItem *) * 2); if(!bag->attribs[i]->attrValue) { PORT_SetError(SEC_ERROR_NO_MEMORY); return SECFailure; } bag->attribs[i+1] = NULL; bag->attribs[i]->attrValue[0] = attrValue; bag->attribs[i]->attrValue[1] = NULL; if(SECITEM_CopyItem(bag->arena, &bag->attribs[i]->attrType, &oid->oid) != SECSuccess) { PORT_SetError(SEC_ERROR_NO_MEMORY); return SECFailure; } return SECSuccess;}static SECItem *sec_pkcs12_get_attribute_value(sec_PKCS12SafeBag *bag, SECOidTag attributeType){ int i = 0; if(!bag->attribs) { return NULL; } while(bag->attribs[i] != NULL) { if(SECOID_FindOIDTag(&bag->attribs[i]->attrType) == attributeType) { return bag->attribs[i]->attrValue[0]; } i++; } return NULL;}/* For now, this function will merely remove any ":" * in the nickname which the PK11 functions may have * placed there. This will keep dual certs from appearing * twice under "Your" certificates when imported onto smart * cards. Once with the name "Slot:Cert" and another with * the nickname "Slot:Slot:Cert" */static voidsec_pkcs12_sanitize_nickname(PK11SlotInfo *slot, SECItem *nick){ char *nickname; char *delimit; int delimitlen; nickname = (char*)nick->data; /*Mac breaks without this type cast*/ if ((delimit = PORT_Strchr(nickname, ':')) != NULL) { char *slotName; int slotNameLen; slotNameLen = delimit-nickname; slotName = PORT_NewArray(char, (slotNameLen+1)); PORT_Assert(slotName); if (slotName == NULL) { /* What else can we do?*/ return; } PORT_Memcpy(slotName, nickname, slotNameLen); slotName[slotNameLen] = '\0'; if (PORT_Strcmp(PK11_GetTokenName(slot), slotName) == 0) { delimitlen = PORT_Strlen(delimit+1); PORT_Memmove(nickname, delimit+1, delimitlen+1); nick->len = delimitlen; } PORT_Free(slotName); } }static SECItem *sec_pkcs12_get_nickname(sec_PKCS12SafeBag *bag){
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?