michael@0: /* -*- Mode: C; tab-width: 8 -*-*/ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: michael@0: #include "crmf.h" michael@0: #include "crmfi.h" michael@0: #include "secitem.h" michael@0: michael@0: static CRMFPOPChoice michael@0: crmf_get_popchoice_from_der(SECItem *derPOP) michael@0: { michael@0: CRMFPOPChoice retChoice; michael@0: michael@0: switch (derPOP->data[0] & 0x0f) { michael@0: case 0: michael@0: retChoice = crmfRAVerified; michael@0: break; michael@0: case 1: michael@0: retChoice = crmfSignature; michael@0: break; michael@0: case 2: michael@0: retChoice = crmfKeyEncipherment; michael@0: break; michael@0: case 3: michael@0: retChoice = crmfKeyAgreement; michael@0: break; michael@0: default: michael@0: retChoice = crmfNoPOPChoice; michael@0: break; michael@0: } michael@0: return retChoice; michael@0: } michael@0: michael@0: static SECStatus michael@0: crmf_decode_process_raverified(CRMFCertReqMsg *inCertReqMsg) michael@0: { michael@0: CRMFProofOfPossession *pop; michael@0: /* Just set up the structure so that the message structure michael@0: * looks like one that was created using the API michael@0: */ michael@0: pop = inCertReqMsg->pop; michael@0: pop->popChoice.raVerified.data = NULL; michael@0: pop->popChoice.raVerified.len = 0; michael@0: return SECSuccess; michael@0: } michael@0: michael@0: static SECStatus michael@0: crmf_decode_process_signature(CRMFCertReqMsg *inCertReqMsg) michael@0: { michael@0: PORT_Assert(inCertReqMsg->poolp); michael@0: if (!inCertReqMsg->poolp) { michael@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); michael@0: return SECFailure; michael@0: } michael@0: return SEC_ASN1Decode(inCertReqMsg->poolp, michael@0: &inCertReqMsg->pop->popChoice.signature, michael@0: CRMFPOPOSigningKeyTemplate, michael@0: (const char*)inCertReqMsg->derPOP.data, michael@0: inCertReqMsg->derPOP.len); michael@0: } michael@0: michael@0: static CRMFPOPOPrivKeyChoice michael@0: crmf_get_messagechoice_from_der(SECItem *derPOP) michael@0: { michael@0: CRMFPOPOPrivKeyChoice retChoice; michael@0: michael@0: switch (derPOP->data[2] & 0x0f) { michael@0: case 0: michael@0: retChoice = crmfThisMessage; michael@0: break; michael@0: case 1: michael@0: retChoice = crmfSubsequentMessage; michael@0: break; michael@0: case 2: michael@0: retChoice = crmfDHMAC; michael@0: break; michael@0: default: michael@0: retChoice = crmfNoMessage; michael@0: } michael@0: return retChoice; michael@0: } michael@0: michael@0: static SECStatus michael@0: crmf_decode_process_popoprivkey(CRMFCertReqMsg *inCertReqMsg) michael@0: { michael@0: /* We've got a union, so a pointer to one POPOPrivKey michael@0: * struct is the same as having a pointer to the other michael@0: * one. michael@0: */ michael@0: CRMFPOPOPrivKey *popoPrivKey = michael@0: &inCertReqMsg->pop->popChoice.keyEncipherment; michael@0: SECItem *derPOP, privKeyDer; michael@0: SECStatus rv; michael@0: michael@0: derPOP = &inCertReqMsg->derPOP; michael@0: popoPrivKey->messageChoice = crmf_get_messagechoice_from_der(derPOP); michael@0: if (popoPrivKey->messageChoice == crmfNoMessage) { michael@0: return SECFailure; michael@0: } michael@0: /* If we ever encounter BER encodings of this, we'll get in trouble*/ michael@0: switch (popoPrivKey->messageChoice) { michael@0: case crmfThisMessage: michael@0: case crmfDHMAC: michael@0: privKeyDer.type = derPOP->type; michael@0: privKeyDer.data = &derPOP->data[5]; michael@0: privKeyDer.len = derPOP->len - 5; michael@0: break; michael@0: case crmfSubsequentMessage: michael@0: privKeyDer.type = derPOP->type; michael@0: privKeyDer.data = &derPOP->data[4]; michael@0: privKeyDer.len = derPOP->len - 4; michael@0: break; michael@0: default: michael@0: return SECFailure; michael@0: } michael@0: michael@0: rv = SECITEM_CopyItem(inCertReqMsg->poolp, michael@0: &popoPrivKey->message.subsequentMessage, michael@0: &privKeyDer); michael@0: michael@0: if (rv != SECSuccess) { michael@0: return rv; michael@0: } michael@0: michael@0: if (popoPrivKey->messageChoice == crmfThisMessage || michael@0: popoPrivKey->messageChoice == crmfDHMAC) { michael@0: michael@0: popoPrivKey->message.thisMessage.len = michael@0: CRMF_BYTES_TO_BITS(privKeyDer.len) - (int)derPOP->data[4]; michael@0: michael@0: } michael@0: return SECSuccess; michael@0: } michael@0: michael@0: static SECStatus michael@0: crmf_decode_process_keyagreement(CRMFCertReqMsg *inCertReqMsg) michael@0: { michael@0: return crmf_decode_process_popoprivkey(inCertReqMsg); michael@0: } michael@0: michael@0: static SECStatus michael@0: crmf_decode_process_keyencipherment(CRMFCertReqMsg *inCertReqMsg) michael@0: { michael@0: SECStatus rv; michael@0: michael@0: rv = crmf_decode_process_popoprivkey(inCertReqMsg); michael@0: if (rv != SECSuccess) { michael@0: return rv; michael@0: } michael@0: if (inCertReqMsg->pop->popChoice.keyEncipherment.messageChoice == michael@0: crmfDHMAC) { michael@0: /* Key Encipherment can not use the dhMAC option for michael@0: * POPOPrivKey. michael@0: */ michael@0: return SECFailure; michael@0: } michael@0: return SECSuccess; michael@0: } michael@0: michael@0: static SECStatus michael@0: crmf_decode_process_pop(CRMFCertReqMsg *inCertReqMsg) michael@0: { michael@0: SECItem *derPOP; michael@0: PLArenaPool *poolp; michael@0: CRMFProofOfPossession *pop; michael@0: void *mark; michael@0: SECStatus rv; michael@0: michael@0: derPOP = &inCertReqMsg->derPOP; michael@0: poolp = inCertReqMsg->poolp; michael@0: if (derPOP->data == NULL) { michael@0: /* There is no Proof of Possession field in this message. */ michael@0: return SECSuccess; michael@0: } michael@0: mark = PORT_ArenaMark(poolp); michael@0: pop = PORT_ArenaZNew(poolp, CRMFProofOfPossession); michael@0: if (pop == NULL) { michael@0: goto loser; michael@0: } michael@0: pop->popUsed = crmf_get_popchoice_from_der(derPOP); michael@0: if (pop->popUsed == crmfNoPOPChoice) { michael@0: /* A bad encoding of CRMF. Not a valid tag was given to the michael@0: * Proof Of Possession field. michael@0: */ michael@0: goto loser; michael@0: } michael@0: inCertReqMsg->pop = pop; michael@0: switch (pop->popUsed) { michael@0: case crmfRAVerified: michael@0: rv = crmf_decode_process_raverified(inCertReqMsg); michael@0: break; michael@0: case crmfSignature: michael@0: rv = crmf_decode_process_signature(inCertReqMsg); michael@0: break; michael@0: case crmfKeyEncipherment: michael@0: rv = crmf_decode_process_keyencipherment(inCertReqMsg); michael@0: break; michael@0: case crmfKeyAgreement: michael@0: rv = crmf_decode_process_keyagreement(inCertReqMsg); michael@0: break; michael@0: default: michael@0: rv = SECFailure; michael@0: } michael@0: if (rv != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: PORT_ArenaUnmark(poolp, mark); michael@0: return SECSuccess; michael@0: michael@0: loser: michael@0: PORT_ArenaRelease(poolp, mark); michael@0: inCertReqMsg->pop = NULL; michael@0: return SECFailure; michael@0: michael@0: } michael@0: michael@0: static SECStatus michael@0: crmf_decode_process_single_control(PLArenaPool *poolp, michael@0: CRMFControl *inControl) michael@0: { michael@0: const SEC_ASN1Template *asn1Template = NULL; michael@0: michael@0: inControl->tag = SECOID_FindOIDTag(&inControl->derTag); michael@0: asn1Template = crmf_get_pkiarchiveoptions_subtemplate(inControl); michael@0: michael@0: PORT_Assert (asn1Template != NULL); michael@0: PORT_Assert (poolp != NULL); michael@0: if (!asn1Template || !poolp) { michael@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); michael@0: return SECFailure; michael@0: } michael@0: /* We've got a union, so passing a pointer to one element of the michael@0: * union is the same as passing a pointer to any of the other michael@0: * members of the union. michael@0: */ michael@0: return SEC_ASN1Decode(poolp, &inControl->value.archiveOptions, michael@0: asn1Template, (const char*)inControl->derValue.data, michael@0: inControl->derValue.len); michael@0: } michael@0: michael@0: static SECStatus michael@0: crmf_decode_process_controls(CRMFCertReqMsg *inCertReqMsg) michael@0: { michael@0: int i, numControls; michael@0: SECStatus rv; michael@0: PLArenaPool *poolp; michael@0: CRMFControl **controls; michael@0: michael@0: numControls = CRMF_CertRequestGetNumControls(inCertReqMsg->certReq); michael@0: controls = inCertReqMsg->certReq->controls; michael@0: poolp = inCertReqMsg->poolp; michael@0: for (i=0; i < numControls; i++) { michael@0: rv = crmf_decode_process_single_control(poolp, controls[i]); michael@0: if (rv != SECSuccess) { michael@0: return SECFailure; michael@0: } michael@0: } michael@0: return SECSuccess; michael@0: } michael@0: michael@0: static SECStatus michael@0: crmf_decode_process_single_reqmsg(CRMFCertReqMsg *inCertReqMsg) michael@0: { michael@0: SECStatus rv; michael@0: michael@0: rv = crmf_decode_process_pop(inCertReqMsg); michael@0: if (rv != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: michael@0: rv = crmf_decode_process_controls(inCertReqMsg); michael@0: if (rv != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: inCertReqMsg->certReq->certTemplate.numExtensions = michael@0: CRMF_CertRequestGetNumberOfExtensions(inCertReqMsg->certReq); michael@0: inCertReqMsg->isDecoded = PR_TRUE; michael@0: rv = SECSuccess; michael@0: loser: michael@0: return rv; michael@0: } michael@0: michael@0: CRMFCertReqMsg* michael@0: CRMF_CreateCertReqMsgFromDER (const char * buf, long len) michael@0: { michael@0: PLArenaPool *poolp; michael@0: CRMFCertReqMsg *certReqMsg; michael@0: SECStatus rv; michael@0: michael@0: poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE); michael@0: if (poolp == NULL) { michael@0: goto loser; michael@0: } michael@0: certReqMsg = PORT_ArenaZNew (poolp, CRMFCertReqMsg); michael@0: if (certReqMsg == NULL) { michael@0: goto loser; michael@0: } michael@0: certReqMsg->poolp = poolp; michael@0: rv = SEC_ASN1Decode(poolp, certReqMsg, CRMFCertReqMsgTemplate, buf, len); michael@0: if (rv != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: michael@0: rv = crmf_decode_process_single_reqmsg(certReqMsg); michael@0: if (rv != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: michael@0: return certReqMsg; michael@0: loser: michael@0: if (poolp != NULL) { michael@0: PORT_FreeArena(poolp, PR_FALSE); michael@0: } michael@0: return NULL; michael@0: } michael@0: michael@0: CRMFCertReqMessages* michael@0: CRMF_CreateCertReqMessagesFromDER(const char *buf, long len) michael@0: { michael@0: long arenaSize; michael@0: int i; michael@0: SECStatus rv; michael@0: PLArenaPool *poolp; michael@0: CRMFCertReqMessages *certReqMsgs; michael@0: michael@0: PORT_Assert (buf != NULL); michael@0: /* Wanna make sure the arena is big enough to store all of the requests michael@0: * coming in. We'll guestimate according to the length of the buffer. michael@0: */ michael@0: arenaSize = len + len/2; michael@0: poolp = PORT_NewArena(arenaSize); michael@0: if (poolp == NULL) { michael@0: return NULL; michael@0: } michael@0: certReqMsgs = PORT_ArenaZNew(poolp, CRMFCertReqMessages); michael@0: if (certReqMsgs == NULL) { michael@0: goto loser; michael@0: } michael@0: certReqMsgs->poolp = poolp; michael@0: rv = SEC_ASN1Decode(poolp, certReqMsgs, CRMFCertReqMessagesTemplate, michael@0: buf, len); michael@0: if (rv != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: for (i=0; certReqMsgs->messages[i] != NULL; i++) { michael@0: /* The sub-routines expect the individual messages to have michael@0: * an arena. We'll give them one temporarily. michael@0: */ michael@0: certReqMsgs->messages[i]->poolp = poolp; michael@0: rv = crmf_decode_process_single_reqmsg(certReqMsgs->messages[i]); michael@0: if (rv != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: certReqMsgs->messages[i]->poolp = NULL; michael@0: } michael@0: return certReqMsgs; michael@0: michael@0: loser: michael@0: PORT_FreeArena(poolp, PR_FALSE); michael@0: return NULL; michael@0: }