crmfpop.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:17k
- /* -*- Mode: C; tab-width: 8 -*-*/
- /*
- * The contents of this file are subject to the Mozilla Public
- * License Version 1.1 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- *
- * The Original Code is the Netscape security libraries.
- *
- * The Initial Developer of the Original Code is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1994-2000 Netscape Communications Corporation. All
- * Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License Version 2 or later (the
- * "GPL"), in which case the provisions of the GPL are applicable
- * instead of those above. If you wish to allow use of your
- * version of this file only under the terms of the GPL and not to
- * allow others to use your version of this file under the MPL,
- * indicate your decision by deleting the provisions above and
- * replace them with the notice and other provisions required by
- * the GPL. If you do not delete the provisions above, a recipient
- * may use your version of this file under either the MPL or the
- * GPL.
- */
- #include "crmf.h"
- #include "crmfi.h"
- #include "secasn1.h"
- #include "keyhi.h"
- #include "cryptohi.h"
- #define CRMF_DEFAULT_ALLOC_SIZE 1024
- SECStatus
- crmf_init_encoder_callback_arg (struct crmfEncoderArg *encoderArg,
- SECItem *derDest)
- {
- derDest->data = PORT_ZNewArray(unsigned char, CRMF_DEFAULT_ALLOC_SIZE);
- if (derDest->data == NULL) {
- return SECFailure;
- }
- derDest->len = 0;
- encoderArg->allocatedLen = CRMF_DEFAULT_ALLOC_SIZE;
- encoderArg->buffer = derDest;
- return SECSuccess;
- }
- /* Caller should release or unmark the pool, instead of doing it here.
- ** But there are NO callers of this function at present...
- */
- SECStatus
- CRMF_CertReqMsgSetRAVerifiedPOP(CRMFCertReqMsg *inCertReqMsg)
- {
- SECItem *dummy;
- CRMFProofOfPossession *pop;
- PRArenaPool *poolp;
- void *mark;
- PORT_Assert(inCertReqMsg != NULL && inCertReqMsg->pop == NULL);
- poolp = inCertReqMsg->poolp;
- mark = PORT_ArenaMark(poolp);
- if (CRMF_CertReqMsgGetPOPType(inCertReqMsg) != crmfNoPOPChoice) {
- return SECFailure;
- }
- pop = PORT_ArenaZNew(poolp, CRMFProofOfPossession);
- if (pop == NULL) {
- goto loser;
- }
- pop->popUsed = crmfRAVerified;
- pop->popChoice.raVerified.data = NULL;
- pop->popChoice.raVerified.len = 0;
- inCertReqMsg->pop = pop;
- dummy = SEC_ASN1EncodeItem(poolp, &(inCertReqMsg->derPOP),
- &(pop->popChoice.raVerified),
- CRMFRAVerifiedTemplate);
- return SECSuccess;
- loser:
- PORT_ArenaRelease(poolp, mark);
- return SECFailure;
- }
- SECOidTag
- crmf_map_keytag_to_signtag(SECOidTag inTag)
- {
- switch (inTag) {
- case SEC_OID_PKCS1_RSA_ENCRYPTION:
- return SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
- case SEC_OID_ANSIX9_DSA_SIGNATURE:
- case SEC_OID_MISSI_KEA_DSS:
- case SEC_OID_MISSI_DSS:
- return SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST;
- default:
- /* Put this in here to kill warnings. */
- break;
- }
- return inTag;
- }
- SECOidTag
- crmf_get_key_sign_tag(SECKEYPublicKey *inPubKey)
- {
- CERTSubjectPublicKeyInfo *spki;
- SECOidTag tag;
- spki = SECKEY_CreateSubjectPublicKeyInfo(inPubKey);
- if (spki == NULL) {
- return SEC_OID_UNKNOWN;
- }
- tag = SECOID_GetAlgorithmTag(&spki->algorithm);
- SECKEY_DestroySubjectPublicKeyInfo(spki);
- return crmf_map_keytag_to_signtag(tag);
- }
- SECAlgorithmID*
- crmf_create_poposignkey_algid(PRArenaPool *poolp,
- SECKEYPublicKey *inPubKey)
- {
- SECAlgorithmID *algID;
- SECOidTag tag;
- SECStatus rv;
- void *mark;
- mark = PORT_ArenaMark(poolp);
- algID = PORT_ArenaZNew(poolp, SECAlgorithmID);
- if (algID == NULL) {
- goto loser;
- }
- tag = crmf_get_key_sign_tag(inPubKey);
- if (tag == SEC_OID_UNKNOWN) {
- goto loser;
- }
- rv = SECOID_SetAlgorithmID(poolp, algID, tag, NULL);
- if (rv != SECSuccess) {
- goto loser;
- }
- PORT_ArenaUnmark(poolp, mark);
- return algID;
- loser:
- PORT_ArenaRelease(poolp, mark);
- return NULL;
- }
- static CRMFPOPOSigningKeyInput*
- crmf_create_poposigningkeyinput(PRArenaPool *poolp, CERTCertificate *inCert,
- CRMFMACPasswordCallback fn, void *arg)
- {
- /* PSM isn't going to do this, so we'll fail here for now.*/
- return NULL;
- }
- void
- crmf_generic_encoder_callback(void *arg, const char* buf, unsigned long len,
- int depth, SEC_ASN1EncodingPart data_kind)
- {
- struct crmfEncoderArg *encoderArg = (struct crmfEncoderArg*)arg;
- unsigned char *cursor;
-
- if (encoderArg->buffer->len + len > encoderArg->allocatedLen) {
- int newSize = encoderArg->buffer->len+CRMF_DEFAULT_ALLOC_SIZE;
- void *dummy = PORT_Realloc(encoderArg->buffer->data, newSize);
- if (dummy == NULL) {
- /* I really want to return an error code here */
- PORT_Assert(0);
- return;
- }
- encoderArg->buffer->data = dummy;
- encoderArg->allocatedLen = newSize;
- }
- cursor = &(encoderArg->buffer->data[encoderArg->buffer->len]);
- PORT_Memcpy (cursor, buf, len);
- encoderArg->buffer->len += len;
- }
- static SECStatus
- crmf_encode_certreq(CRMFCertRequest *inCertReq, SECItem *derDest)
- {
- struct crmfEncoderArg encoderArg;
- SECStatus rv;
-
- rv = crmf_init_encoder_callback_arg (&encoderArg, derDest);
- if (rv != SECSuccess) {
- return SECFailure;
- }
- return SEC_ASN1Encode(inCertReq, CRMFCertRequestTemplate,
- crmf_generic_encoder_callback, &encoderArg);
- }
- static SECStatus
- crmf_sign_certreq(PRArenaPool *poolp,
- CRMFPOPOSigningKey *crmfSignKey,
- CRMFCertRequest *certReq,
- SECKEYPrivateKey *inKey,
- SECAlgorithmID *inAlgId)
- {
- SECItem derCertReq;
- SECItem certReqSig;
- SECStatus rv = SECSuccess;
- rv = crmf_encode_certreq(certReq, &derCertReq);
- if (rv != SECSuccess) {
- goto loser;
- }
- rv = SEC_SignData(&certReqSig, derCertReq.data, derCertReq.len,
- inKey,SECOID_GetAlgorithmTag(inAlgId));
- if (rv != SECSuccess) {
- goto loser;
- }
-
- /* Now make it a part of the POPOSigningKey */
- rv = SECITEM_CopyItem(poolp, &(crmfSignKey->signature), &certReqSig);
- /* Convert this length to number of bits */
- crmfSignKey->signature.len <<= 3;
-
- loser:
- if (derCertReq.data != NULL) {
- PORT_Free(derCertReq.data);
- }
- if (certReqSig.data != NULL) {
- PORT_Free(certReqSig.data);
- }
- return rv;
- }
- static SECStatus
- crmf_create_poposignkey(PRArenaPool *poolp,
- CRMFCertReqMsg *inCertReqMsg,
- CRMFPOPOSigningKeyInput *signKeyInput,
- SECKEYPrivateKey *inPrivKey,
- SECAlgorithmID *inAlgID,
- CRMFPOPOSigningKey *signKey)
- {
- CRMFCertRequest *certReq;
- void *mark;
- PRBool useSignKeyInput;
- SECStatus rv;
-
- PORT_Assert(inCertReqMsg != NULL && inCertReqMsg->certReq != NULL);
- mark = PORT_ArenaMark(poolp);
- if (signKey == NULL) {
- goto loser;
- }
- certReq = inCertReqMsg->certReq;
- useSignKeyInput = !(CRMF_DoesRequestHaveField(certReq,crmfSubject) &&
- CRMF_DoesRequestHaveField(certReq,crmfPublicKey));
- if (useSignKeyInput) {
- goto loser;
- } else {
- rv = crmf_sign_certreq(poolp, signKey, certReq,inPrivKey, inAlgID);
- if (rv != SECSuccess) {
- goto loser;
- }
- }
- PORT_ArenaUnmark(poolp,mark);
- return SECSuccess;
- loser:
- PORT_ArenaRelease(poolp,mark);
- return SECFailure;
- }
- SECStatus
- CRMF_CertReqMsgSetSignaturePOP(CRMFCertReqMsg *inCertReqMsg,
- SECKEYPrivateKey *inPrivKey,
- SECKEYPublicKey *inPubKey,
- CERTCertificate *inCertForInput,
- CRMFMACPasswordCallback fn,
- void *arg)
- {
- SECAlgorithmID *algID;
- PRArenaPool *poolp;
- SECItem derDest = {siBuffer, NULL, 0};
- void *mark;
- SECStatus rv;
- CRMFPOPOSigningKeyInput *signKeyInput = NULL;
- CRMFCertRequest *certReq;
- CRMFProofOfPossession *pop;
- struct crmfEncoderArg encoderArg;
- PORT_Assert(inCertReqMsg != NULL && inCertReqMsg->certReq != NULL &&
- inCertReqMsg->pop == NULL);
- certReq = inCertReqMsg->certReq;
- if (CRMF_CertReqMsgGetPOPType(inCertReqMsg) != crmfNoPOPChoice ||
- !CRMF_DoesRequestHaveField(certReq, crmfPublicKey)) {
- return SECFailure;
- }
- poolp = inCertReqMsg->poolp;
- mark = PORT_ArenaMark(poolp);
- algID = crmf_create_poposignkey_algid(poolp, inPubKey);
- if(!CRMF_DoesRequestHaveField(certReq,crmfSubject)) {
- signKeyInput = crmf_create_poposigningkeyinput(poolp, inCertForInput,
- fn, arg);
- if (signKeyInput == NULL) {
- goto loser;
- }
- }
- pop = PORT_ArenaZNew(poolp, CRMFProofOfPossession);
- if (pop == NULL) {
- goto loser;
- }
-
- rv = crmf_create_poposignkey(poolp, inCertReqMsg,
- signKeyInput, inPrivKey, algID,
- &(pop->popChoice.signature));
- if (rv != SECSuccess) {
- goto loser;
- }
- pop->popUsed = crmfSignature;
- pop->popChoice.signature.algorithmIdentifier = algID;
- inCertReqMsg->pop = pop;
-
- rv = crmf_init_encoder_callback_arg (&encoderArg, &derDest);
- if (rv != SECSuccess) {
- goto loser;
- }
- rv = SEC_ASN1Encode(&pop->popChoice.signature,
- CRMFPOPOSigningKeyTemplate,
- crmf_generic_encoder_callback, &encoderArg);
- if (rv != SECSuccess) {
- goto loser;
- }
- rv = SECITEM_CopyItem(poolp, &(inCertReqMsg->derPOP), &derDest);
- PORT_Free (derDest.data);
- if (rv != SECSuccess) {
- goto loser;
- }
- PORT_ArenaUnmark(poolp,mark);
- return SECSuccess;
- loser:
- PORT_ArenaRelease(poolp,mark);
- if (derDest.data != NULL) {
- PORT_Free(derDest.data);
- }
- return SECFailure;
- }
- static const SEC_ASN1Template*
- crmf_get_popoprivkey_subtemplate(CRMFPOPOPrivKey *inPrivKey)
- {
- const SEC_ASN1Template *retTemplate = NULL;
- switch (inPrivKey->messageChoice) {
- case crmfThisMessage:
- retTemplate = CRMFThisMessageTemplate;
- break;
- case crmfSubsequentMessage:
- retTemplate = CRMFSubsequentMessageTemplate;
- break;
- case crmfDHMAC:
- retTemplate = CRMFDHMACTemplate;
- break;
- default:
- retTemplate = NULL;
- }
- return retTemplate;
- }
- static SECStatus
- crmf_encode_popoprivkey(PRArenaPool *poolp,
- CRMFCertReqMsg *inCertReqMsg,
- CRMFPOPOPrivKey *popoPrivKey,
- const SEC_ASN1Template *privKeyTemplate)
- {
- struct crmfEncoderArg encoderArg;
- SECItem derDest;
- SECStatus rv;
- void *mark;
- const SEC_ASN1Template *subDerTemplate;
- mark = PORT_ArenaMark(poolp);
- rv = crmf_init_encoder_callback_arg(&encoderArg, &derDest);
- if (rv != SECSuccess) {
- goto loser;
- }
- subDerTemplate = crmf_get_popoprivkey_subtemplate(popoPrivKey);
- /* We've got a union, so a pointer to one item is a pointer to
- * all the items in the union.
- */
- rv = SEC_ASN1Encode(&popoPrivKey->message.thisMessage,
- subDerTemplate,
- crmf_generic_encoder_callback, &encoderArg);
- if (rv != SECSuccess) {
- goto loser;
- }
- if (encoderArg.allocatedLen > derDest.len+2) {
- void *dummy = PORT_Realloc(derDest.data, derDest.len+2);
- if (dummy == NULL) {
- goto loser;
- }
- derDest.data = dummy;
- }
- PORT_Memmove(&derDest.data[2], &derDest.data[0], derDest.len);
- /* I couldn't figure out how to get the ASN1 encoder to implicitly
- * tag an implicitly tagged der blob. So I'm putting in the outter-
- * most tag myself. -javi
- */
- derDest.data[0] = (unsigned char)privKeyTemplate->kind;
- derDest.data[1] = (unsigned char)derDest.len;
- derDest.len += 2;
- rv = SECITEM_CopyItem(poolp, &inCertReqMsg->derPOP, &derDest);
- if (rv != SECSuccess) {
- goto loser;
- }
- PORT_Free(derDest.data);
- PORT_ArenaUnmark(poolp, mark);
- return SECSuccess;
- loser:
- PORT_ArenaRelease(poolp, mark);
- if (derDest.data) {
- PORT_Free(derDest.data);
- }
- return SECFailure;
- }
- static const SEC_ASN1Template*
- crmf_get_template_for_privkey(CRMFPOPChoice inChoice)
- {
- switch (inChoice) {
- case crmfKeyAgreement:
- return CRMFPOPOKeyAgreementTemplate;
- case crmfKeyEncipherment:
- return CRMFPOPOKeyEnciphermentTemplate;
- default:
- break;
- }
- return NULL;
- }
- static SECStatus
- crmf_add_privkey_thismessage(CRMFCertReqMsg *inCertReqMsg, SECItem *encPrivKey,
- CRMFPOPChoice inChoice)
- {
- PRArenaPool *poolp;
- void *mark;
- CRMFPOPOPrivKey *popoPrivKey;
- CRMFProofOfPossession *pop;
- SECStatus rv;
- PORT_Assert(inCertReqMsg != NULL && encPrivKey != NULL);
- poolp = inCertReqMsg->poolp;
- mark = PORT_ArenaMark(poolp);
- pop = PORT_ArenaZNew(poolp, CRMFProofOfPossession);
- if (pop == NULL) {
- goto loser;
- }
- pop->popUsed = inChoice;
- /* popChoice is a union, so getting a pointer to one
- * field gives me a pointer to the other fields as
- * well. This in essence points to both
- * pop->popChoice.keyEncipherment and
- * pop->popChoice.keyAgreement
- */
- popoPrivKey = &pop->popChoice.keyEncipherment;
- rv = SECITEM_CopyItem(poolp, &(popoPrivKey->message.thisMessage),
- encPrivKey);
- if (rv != SECSuccess) {
- goto loser;
- }
- popoPrivKey->message.thisMessage.len <<= 3;
- popoPrivKey->messageChoice = crmfThisMessage;
- inCertReqMsg->pop = pop;
- rv = crmf_encode_popoprivkey(poolp, inCertReqMsg, popoPrivKey,
- crmf_get_template_for_privkey(inChoice));
- if (rv != SECSuccess) {
- goto loser;
- }
- PORT_ArenaUnmark(poolp, mark);
- return SECSuccess;
-
- loser:
- PORT_ArenaRelease(poolp, mark);
- return SECFailure;
- }
- static SECStatus
- crmf_add_privkey_subseqmessage(CRMFCertReqMsg *inCertReqMsg,
- CRMFSubseqMessOptions subsequentMessage,
- CRMFPOPChoice inChoice)
- {
- void *mark;
- PRArenaPool *poolp;
- CRMFProofOfPossession *pop;
- CRMFPOPOPrivKey *popoPrivKey;
- SECStatus rv;
- const SEC_ASN1Template *privKeyTemplate;
- if (subsequentMessage == crmfNoSubseqMess) {
- return SECFailure;
- }
- poolp = inCertReqMsg->poolp;
- mark = PORT_ArenaMark(poolp);
- pop = PORT_ArenaZNew(poolp, CRMFProofOfPossession);
- if (pop == NULL) {
- goto loser;
- }
- pop->popUsed = inChoice;
- /*
- * We have a union, so a pointer to one member of the union
- * is also a member to another member of that same union.
- */
- popoPrivKey = &pop->popChoice.keyEncipherment;
- switch (subsequentMessage) {
- case crmfEncrCert:
- rv = crmf_encode_integer(poolp,
- &(popoPrivKey->message.subsequentMessage),
- 0);
- break;
- case crmfChallengeResp:
- rv = crmf_encode_integer(poolp,
- &(popoPrivKey->message.subsequentMessage),
- 1);
- break;
- default:
- goto loser;
- }
- if (rv != SECSuccess) {
- goto loser;
- }
- popoPrivKey->messageChoice = crmfSubsequentMessage;
- privKeyTemplate = crmf_get_template_for_privkey(inChoice);
- inCertReqMsg->pop = pop;
- rv = crmf_encode_popoprivkey(poolp, inCertReqMsg, popoPrivKey,
- privKeyTemplate);
- if (rv != SECSuccess) {
- goto loser;
- }
- PORT_ArenaUnmark(poolp, mark);
- return SECSuccess;
- loser:
- PORT_ArenaRelease(poolp, mark);
- return SECFailure;
- }
- SECStatus
- CRMF_CertReqMsgSetKeyEnciphermentPOP(CRMFCertReqMsg *inCertReqMsg,
- CRMFPOPOPrivKeyChoice inKeyChoice,
- CRMFSubseqMessOptions subseqMess,
- SECItem *encPrivKey)
- {
- SECStatus rv;
- PORT_Assert(inCertReqMsg != NULL && inCertReqMsg->pop == NULL);
- if (CRMF_CertReqMsgGetPOPType(inCertReqMsg) != crmfNoPOPChoice) {
- return SECFailure;
- }
- switch (inKeyChoice) {
- case crmfThisMessage:
- rv = crmf_add_privkey_thismessage(inCertReqMsg, encPrivKey,
- crmfKeyEncipherment);
- break;
- case crmfSubsequentMessage:
- rv = crmf_add_privkey_subseqmessage(inCertReqMsg, subseqMess,
- crmfKeyEncipherment);
- break;
- case crmfDHMAC:
- default:
- rv = SECFailure;
- }
- return rv;
- }
- SECStatus
- CRMF_CertReqMsgSetKeyAgreementPOP (CRMFCertReqMsg *inCertReqMsg,
- CRMFPOPOPrivKeyChoice inKeyChoice,
- CRMFSubseqMessOptions subseqMess,
- SECItem *encPrivKey)
- {
- SECStatus rv;
- PORT_Assert(inCertReqMsg != NULL && inCertReqMsg->pop == NULL);
- switch (inKeyChoice) {
- case crmfThisMessage:
- rv = crmf_add_privkey_thismessage(inCertReqMsg, encPrivKey,
- crmfKeyAgreement);
- break;
- case crmfSubsequentMessage:
- rv = crmf_add_privkey_subseqmessage(inCertReqMsg, subseqMess,
- crmfKeyAgreement);
- case crmfDHMAC:
- /* This case should be added in the future. */
- default:
- rv = SECFailure;
- }
- return rv;
- }