Blame nss/lib/crmf/crmfpop.c

Packit 40b132
/* -*- Mode: C; tab-width: 8 -*-*/
Packit 40b132
/* This Source Code Form is subject to the terms of the Mozilla Public
Packit 40b132
 * License, v. 2.0. If a copy of the MPL was not distributed with this
Packit 40b132
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Packit 40b132
Packit 40b132
Packit 40b132
#include "crmf.h"
Packit 40b132
#include "crmfi.h"
Packit 40b132
#include "secasn1.h"
Packit 40b132
#include "keyhi.h"
Packit 40b132
#include "cryptohi.h"
Packit 40b132
Packit 40b132
#define CRMF_DEFAULT_ALLOC_SIZE 1024
Packit 40b132
Packit 40b132
SECStatus
Packit 40b132
crmf_init_encoder_callback_arg (struct crmfEncoderArg *encoderArg, 
Packit 40b132
				SECItem               *derDest) 
Packit 40b132
{
Packit 40b132
    derDest->data = PORT_ZNewArray(unsigned char, CRMF_DEFAULT_ALLOC_SIZE);
Packit 40b132
    if (derDest->data == NULL) {
Packit 40b132
        return SECFailure;
Packit 40b132
    }
Packit 40b132
    derDest->len = 0;
Packit 40b132
    encoderArg->allocatedLen = CRMF_DEFAULT_ALLOC_SIZE;
Packit 40b132
    encoderArg->buffer = derDest;
Packit 40b132
    return SECSuccess;
Packit 40b132
Packit 40b132
}
Packit 40b132
Packit 40b132
/* Caller should release or unmark the pool, instead of doing it here.
Packit 40b132
** But there are NO callers of this function at present...
Packit 40b132
*/
Packit 40b132
SECStatus 
Packit 40b132
CRMF_CertReqMsgSetRAVerifiedPOP(CRMFCertReqMsg *inCertReqMsg)
Packit 40b132
{
Packit 40b132
    SECItem               *dummy;
Packit 40b132
    CRMFProofOfPossession *pop;
Packit 40b132
    PLArenaPool           *poolp;
Packit 40b132
    void                  *mark;
Packit 40b132
Packit 40b132
    PORT_Assert(inCertReqMsg != NULL && inCertReqMsg->pop == NULL);
Packit 40b132
    poolp = inCertReqMsg->poolp;
Packit 40b132
    mark = PORT_ArenaMark(poolp);
Packit 40b132
    if (CRMF_CertReqMsgGetPOPType(inCertReqMsg) != crmfNoPOPChoice) {
Packit 40b132
        return SECFailure;
Packit 40b132
    }
Packit 40b132
    pop = PORT_ArenaZNew(poolp, CRMFProofOfPossession);
Packit 40b132
    if (pop == NULL) {
Packit 40b132
        goto loser;
Packit 40b132
    }
Packit 40b132
    pop->popUsed = crmfRAVerified;
Packit 40b132
    pop->popChoice.raVerified.data = NULL;
Packit 40b132
    pop->popChoice.raVerified.len  = 0;
Packit 40b132
    inCertReqMsg->pop = pop;
Packit 40b132
    dummy = SEC_ASN1EncodeItem(poolp, &(inCertReqMsg->derPOP),
Packit 40b132
			       &(pop->popChoice.raVerified),
Packit 40b132
			       CRMFRAVerifiedTemplate);
Packit 40b132
    return SECSuccess;
Packit 40b132
 loser:
Packit 40b132
    PORT_ArenaRelease(poolp, mark);
Packit 40b132
    return SECFailure;
Packit 40b132
}
Packit 40b132
Packit 40b132
static SECOidTag
Packit 40b132
crmf_get_key_sign_tag(SECKEYPublicKey *inPubKey)
Packit 40b132
{
Packit 40b132
    /* maintain backward compatibility with older
Packit 40b132
     * implementations */
Packit 40b132
    if (inPubKey->keyType == rsaKey) {
Packit 40b132
        return SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
Packit 40b132
    }
Packit 40b132
    return SEC_GetSignatureAlgorithmOidTag(inPubKey->keyType, SEC_OID_UNKNOWN);
Packit 40b132
}
Packit 40b132
Packit 40b132
static SECAlgorithmID*
Packit 40b132
crmf_create_poposignkey_algid(PLArenaPool      *poolp,
Packit 40b132
			      SECKEYPublicKey  *inPubKey)
Packit 40b132
{
Packit 40b132
    SECAlgorithmID *algID;
Packit 40b132
    SECOidTag       tag;
Packit 40b132
    SECStatus       rv;
Packit 40b132
    void           *mark;
Packit 40b132
Packit 40b132
    mark = PORT_ArenaMark(poolp);
Packit 40b132
    algID = PORT_ArenaZNew(poolp, SECAlgorithmID);
Packit 40b132
    if (algID == NULL) {
Packit 40b132
        goto loser;
Packit 40b132
    }
Packit 40b132
    tag = crmf_get_key_sign_tag(inPubKey);
Packit 40b132
    if (tag == SEC_OID_UNKNOWN) {
Packit 40b132
        goto loser;
Packit 40b132
    }
Packit 40b132
    rv = SECOID_SetAlgorithmID(poolp, algID, tag, NULL);
Packit 40b132
    if (rv != SECSuccess) {
Packit 40b132
        goto loser;
Packit 40b132
    }
Packit 40b132
    PORT_ArenaUnmark(poolp, mark);
Packit 40b132
    return algID;
Packit 40b132
 loser:
Packit 40b132
    PORT_ArenaRelease(poolp, mark);
Packit 40b132
    return NULL;
Packit 40b132
}
Packit 40b132
Packit 40b132
static CRMFPOPOSigningKeyInput*
Packit 40b132
crmf_create_poposigningkeyinput(PLArenaPool *poolp, CERTCertificate *inCert,
Packit 40b132
				CRMFMACPasswordCallback fn, void *arg)
Packit 40b132
{
Packit 40b132
  /* PSM isn't going to do this, so we'll fail here for now.*/
Packit 40b132
     return NULL;
Packit 40b132
}
Packit 40b132
Packit 40b132
void
Packit 40b132
crmf_generic_encoder_callback(void *arg, const char* buf, unsigned long len,
Packit 40b132
			      int depth, SEC_ASN1EncodingPart data_kind)
Packit 40b132
{
Packit 40b132
    struct crmfEncoderArg *encoderArg = (struct crmfEncoderArg*)arg;
Packit 40b132
    unsigned char *cursor;
Packit 40b132
    
Packit 40b132
   if (encoderArg->buffer->len + len > encoderArg->allocatedLen) {
Packit 40b132
        int newSize = encoderArg->buffer->len+CRMF_DEFAULT_ALLOC_SIZE;
Packit 40b132
        void *dummy = PORT_Realloc(encoderArg->buffer->data, newSize);
Packit 40b132
	if (dummy == NULL) {
Packit 40b132
	    /* I really want to return an error code here */
Packit 40b132
	    PORT_Assert(0);
Packit 40b132
	    return;
Packit 40b132
	}
Packit 40b132
	encoderArg->buffer->data = dummy;
Packit 40b132
	encoderArg->allocatedLen = newSize;
Packit 40b132
    }
Packit 40b132
    cursor = &(encoderArg->buffer->data[encoderArg->buffer->len]);
Packit 40b132
    PORT_Memcpy (cursor, buf, len);
Packit 40b132
    encoderArg->buffer->len += len;    
Packit 40b132
}
Packit 40b132
Packit 40b132
static SECStatus
Packit 40b132
crmf_encode_certreq(CRMFCertRequest *inCertReq, SECItem *derDest)
Packit 40b132
{
Packit 40b132
    struct crmfEncoderArg encoderArg;
Packit 40b132
    SECStatus             rv;
Packit 40b132
  
Packit 40b132
    rv = crmf_init_encoder_callback_arg (&encoderArg, derDest);
Packit 40b132
    if (rv != SECSuccess) {
Packit 40b132
        return SECFailure;
Packit 40b132
    }
Packit 40b132
    return SEC_ASN1Encode(inCertReq, CRMFCertRequestTemplate, 
Packit 40b132
			  crmf_generic_encoder_callback, &encoderArg);
Packit 40b132
}
Packit 40b132
Packit 40b132
static SECStatus
Packit 40b132
crmf_sign_certreq(PLArenaPool        *poolp,
Packit 40b132
		  CRMFPOPOSigningKey *crmfSignKey, 
Packit 40b132
		  CRMFCertRequest    *certReq,
Packit 40b132
		  SECKEYPrivateKey   *inKey,
Packit 40b132
		  SECAlgorithmID     *inAlgId)
Packit 40b132
{
Packit 40b132
    SECItem                      derCertReq = { siBuffer, NULL, 0 };
Packit 40b132
    SECItem                      certReqSig = { siBuffer, NULL, 0 };
Packit 40b132
    SECStatus                    rv = SECSuccess;
Packit 40b132
Packit 40b132
    rv = crmf_encode_certreq(certReq, &derCertReq);
Packit 40b132
    if (rv != SECSuccess) {
Packit 40b132
       goto loser;
Packit 40b132
    }
Packit 40b132
    rv = SEC_SignData(&certReqSig, derCertReq.data, derCertReq.len,
Packit 40b132
		      inKey,SECOID_GetAlgorithmTag(inAlgId));
Packit 40b132
    if (rv != SECSuccess) {
Packit 40b132
        goto loser;
Packit 40b132
    }
Packit 40b132
 
Packit 40b132
    /* Now make it a part of the POPOSigningKey */
Packit 40b132
    rv = SECITEM_CopyItem(poolp, &(crmfSignKey->signature), &certReqSig);
Packit 40b132
    /* Convert this length to number of bits */
Packit 40b132
    crmfSignKey->signature.len <<= 3; 
Packit 40b132
   
Packit 40b132
 loser:
Packit 40b132
    if (derCertReq.data != NULL) {
Packit 40b132
        PORT_Free(derCertReq.data);
Packit 40b132
    }
Packit 40b132
    if (certReqSig.data != NULL) {
Packit 40b132
        PORT_Free(certReqSig.data);
Packit 40b132
    }
Packit 40b132
    return rv;
Packit 40b132
}
Packit 40b132
Packit 40b132
static SECStatus
Packit 40b132
crmf_create_poposignkey(PLArenaPool             *poolp,
Packit 40b132
			CRMFCertReqMsg          *inCertReqMsg, 
Packit 40b132
			CRMFPOPOSigningKeyInput *signKeyInput, 
Packit 40b132
			SECKEYPrivateKey        *inPrivKey,
Packit 40b132
			SECAlgorithmID          *inAlgID,
Packit 40b132
			CRMFPOPOSigningKey      *signKey) 
Packit 40b132
{
Packit 40b132
    CRMFCertRequest    *certReq;
Packit 40b132
    void               *mark;
Packit 40b132
    PRBool              useSignKeyInput;
Packit 40b132
    SECStatus           rv;
Packit 40b132
    
Packit 40b132
    PORT_Assert(inCertReqMsg != NULL && inCertReqMsg->certReq != NULL);
Packit 40b132
    mark = PORT_ArenaMark(poolp);
Packit 40b132
    if (signKey == NULL) {
Packit 40b132
        goto loser;
Packit 40b132
    }
Packit 40b132
    certReq = inCertReqMsg->certReq;
Packit 40b132
    useSignKeyInput = !(CRMF_DoesRequestHaveField(certReq,crmfSubject)  &&
Packit 40b132
			CRMF_DoesRequestHaveField(certReq,crmfPublicKey));
Packit 40b132
Packit 40b132
    if (useSignKeyInput) {
Packit 40b132
        goto loser; 
Packit 40b132
    } else {
Packit 40b132
        rv = crmf_sign_certreq(poolp, signKey, certReq,inPrivKey, inAlgID);
Packit 40b132
	if (rv != SECSuccess) {
Packit 40b132
	    goto loser;
Packit 40b132
	}
Packit 40b132
    }
Packit 40b132
    PORT_ArenaUnmark(poolp,mark);
Packit 40b132
    return SECSuccess;
Packit 40b132
 loser:
Packit 40b132
    PORT_ArenaRelease(poolp,mark);
Packit 40b132
    return SECFailure;
Packit 40b132
}
Packit 40b132
Packit 40b132
SECStatus
Packit 40b132
CRMF_CertReqMsgSetSignaturePOP(CRMFCertReqMsg   *inCertReqMsg,
Packit 40b132
			       SECKEYPrivateKey *inPrivKey,
Packit 40b132
			       SECKEYPublicKey  *inPubKey,
Packit 40b132
			       CERTCertificate  *inCertForInput,
Packit 40b132
			       CRMFMACPasswordCallback  fn,
Packit 40b132
			       void                    *arg)
Packit 40b132
{
Packit 40b132
    SECAlgorithmID  *algID;
Packit 40b132
    PLArenaPool     *poolp;
Packit 40b132
    SECItem          derTemp = {siBuffer, NULL, 0};
Packit 40b132
    void            *mark;
Packit 40b132
    SECStatus        rv;
Packit 40b132
    CRMFPOPOSigningKeyInput *signKeyInput = NULL;
Packit 40b132
    CRMFCertRequest         *certReq;
Packit 40b132
    CRMFProofOfPossession   *pop;
Packit 40b132
    struct crmfEncoderArg    encoderArg;
Packit 40b132
Packit 40b132
    PORT_Assert(inCertReqMsg != NULL && inCertReqMsg->certReq != NULL &&
Packit 40b132
		inCertReqMsg->pop == NULL);
Packit 40b132
    certReq = inCertReqMsg->certReq;
Packit 40b132
    if (CRMF_CertReqMsgGetPOPType(inCertReqMsg) != crmfNoPOPChoice || 
Packit 40b132
	!CRMF_DoesRequestHaveField(certReq, crmfPublicKey)) {
Packit 40b132
        return SECFailure;
Packit 40b132
    } 
Packit 40b132
    poolp = inCertReqMsg->poolp;
Packit 40b132
    mark = PORT_ArenaMark(poolp);
Packit 40b132
    algID = crmf_create_poposignkey_algid(poolp, inPubKey);
Packit 40b132
Packit 40b132
    if(!CRMF_DoesRequestHaveField(certReq,crmfSubject)) {
Packit 40b132
        signKeyInput = crmf_create_poposigningkeyinput(poolp, inCertForInput,
Packit 40b132
						       fn, arg);
Packit 40b132
	if (signKeyInput == NULL) {
Packit 40b132
	    goto loser;
Packit 40b132
	}
Packit 40b132
    }
Packit 40b132
Packit 40b132
    pop = PORT_ArenaZNew(poolp, CRMFProofOfPossession);
Packit 40b132
    if (pop == NULL) {
Packit 40b132
        goto loser;
Packit 40b132
    }
Packit 40b132
    
Packit 40b132
    rv = crmf_create_poposignkey(poolp, inCertReqMsg, 
Packit 40b132
				 signKeyInput, inPrivKey, algID,
Packit 40b132
				 &(pop->popChoice.signature));
Packit 40b132
    if (rv != SECSuccess) {
Packit 40b132
        goto loser;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    pop->popUsed = crmfSignature;
Packit 40b132
    pop->popChoice.signature.algorithmIdentifier = algID;
Packit 40b132
    inCertReqMsg->pop = pop;
Packit 40b132
  
Packit 40b132
    rv = crmf_init_encoder_callback_arg (&encoderArg, &derTemp);
Packit 40b132
    if (rv != SECSuccess) {
Packit 40b132
        goto loser;
Packit 40b132
    }
Packit 40b132
    rv = SEC_ASN1Encode(&pop->popChoice.signature, 
Packit 40b132
			CRMFPOPOSigningKeyTemplate,
Packit 40b132
			crmf_generic_encoder_callback, &encoderArg);
Packit 40b132
    if (rv != SECSuccess) {
Packit 40b132
        goto loser;
Packit 40b132
    }
Packit 40b132
    rv = SECITEM_CopyItem(poolp, &(inCertReqMsg->derPOP), &derTemp);
Packit 40b132
    if (rv != SECSuccess) {
Packit 40b132
        goto loser;
Packit 40b132
    }
Packit 40b132
    PORT_Free (derTemp.data);
Packit 40b132
    PORT_ArenaUnmark(poolp,mark);
Packit 40b132
    return SECSuccess;
Packit 40b132
Packit 40b132
 loser:
Packit 40b132
    PORT_ArenaRelease(poolp,mark);
Packit 40b132
    if (derTemp.data != NULL) {
Packit 40b132
        PORT_Free(derTemp.data);
Packit 40b132
    }
Packit 40b132
    return SECFailure;
Packit 40b132
}
Packit 40b132
Packit 40b132
static const SEC_ASN1Template*
Packit 40b132
crmf_get_popoprivkey_subtemplate(CRMFPOPOPrivKey *inPrivKey) 
Packit 40b132
{
Packit 40b132
    const SEC_ASN1Template *retTemplate = NULL;
Packit 40b132
Packit 40b132
    switch (inPrivKey->messageChoice) {
Packit 40b132
    case crmfThisMessage:
Packit 40b132
        retTemplate = CRMFThisMessageTemplate;
Packit 40b132
	break;
Packit 40b132
    case crmfSubsequentMessage:
Packit 40b132
        retTemplate = CRMFSubsequentMessageTemplate;
Packit 40b132
	break;
Packit 40b132
    case crmfDHMAC:
Packit 40b132
        retTemplate = CRMFDHMACTemplate;
Packit 40b132
	break;
Packit 40b132
    default:
Packit 40b132
        retTemplate = NULL;
Packit 40b132
    }
Packit 40b132
    return retTemplate;
Packit 40b132
}
Packit 40b132
Packit 40b132
static SECStatus
Packit 40b132
crmf_encode_popoprivkey(PLArenaPool            *poolp,
Packit 40b132
			CRMFCertReqMsg         *inCertReqMsg,
Packit 40b132
			CRMFPOPOPrivKey        *popoPrivKey,
Packit 40b132
			const SEC_ASN1Template *privKeyTemplate)
Packit 40b132
{
Packit 40b132
    struct crmfEncoderArg   encoderArg;
Packit 40b132
    SECItem                 derTemp = { siBuffer, NULL, 0 };
Packit 40b132
    SECStatus               rv;
Packit 40b132
    void                   *mark;
Packit 40b132
    const SEC_ASN1Template *subDerTemplate;
Packit 40b132
Packit 40b132
    mark = PORT_ArenaMark(poolp);
Packit 40b132
    rv = crmf_init_encoder_callback_arg(&encoderArg, &derTemp);
Packit 40b132
    if (rv != SECSuccess) {
Packit 40b132
        goto loser;
Packit 40b132
    }
Packit 40b132
    subDerTemplate = crmf_get_popoprivkey_subtemplate(popoPrivKey);
Packit 40b132
    /* We've got a union, so a pointer to one item is a pointer to 
Packit 40b132
     * all the items in the union.
Packit 40b132
     */
Packit 40b132
    rv = SEC_ASN1Encode(&popoPrivKey->message.thisMessage, 
Packit 40b132
			subDerTemplate,
Packit 40b132
			crmf_generic_encoder_callback, &encoderArg);
Packit 40b132
    if (rv != SECSuccess) {
Packit 40b132
        goto loser;
Packit 40b132
    }
Packit 40b132
    if (encoderArg.allocatedLen > derTemp.len+2) {
Packit 40b132
        void *dummy = PORT_Realloc(derTemp.data, derTemp.len+2);
Packit 40b132
	if (dummy == NULL) {
Packit 40b132
	    goto loser;
Packit 40b132
	}
Packit 40b132
	derTemp.data = dummy;
Packit 40b132
    }
Packit 40b132
    PORT_Memmove(&derTemp.data[2], &derTemp.data[0], derTemp.len);
Packit 40b132
    /* I couldn't figure out how to get the ASN1 encoder to implicitly
Packit 40b132
     * tag an implicitly tagged der blob.  So I'm putting in the outter-
Packit 40b132
     * most tag myself. -javi
Packit 40b132
     */
Packit 40b132
    derTemp.data[0] = (unsigned char)privKeyTemplate->kind;
Packit 40b132
    derTemp.data[1] = (unsigned char)derTemp.len;
Packit 40b132
    derTemp.len += 2;
Packit 40b132
    rv = SECITEM_CopyItem(poolp, &inCertReqMsg->derPOP, &derTemp);
Packit 40b132
    if (rv != SECSuccess) {
Packit 40b132
        goto loser;
Packit 40b132
    }
Packit 40b132
    PORT_Free(derTemp.data);
Packit 40b132
    PORT_ArenaUnmark(poolp, mark);
Packit 40b132
    return SECSuccess;
Packit 40b132
 loser:
Packit 40b132
    PORT_ArenaRelease(poolp, mark);
Packit 40b132
    if (derTemp.data) {
Packit 40b132
        PORT_Free(derTemp.data);
Packit 40b132
    }
Packit 40b132
    return SECFailure;
Packit 40b132
}
Packit 40b132
Packit 40b132
static const SEC_ASN1Template*
Packit 40b132
crmf_get_template_for_privkey(CRMFPOPChoice inChoice) 
Packit 40b132
{
Packit 40b132
    switch (inChoice) {
Packit 40b132
    case crmfKeyAgreement:
Packit 40b132
        return CRMFPOPOKeyAgreementTemplate;
Packit 40b132
    case crmfKeyEncipherment:
Packit 40b132
        return CRMFPOPOKeyEnciphermentTemplate;
Packit 40b132
    default:
Packit 40b132
        break;
Packit 40b132
    }
Packit 40b132
    return NULL;
Packit 40b132
}
Packit 40b132
Packit 40b132
static SECStatus
Packit 40b132
crmf_add_privkey_thismessage(CRMFCertReqMsg *inCertReqMsg, SECItem *encPrivKey,
Packit 40b132
			     CRMFPOPChoice inChoice)
Packit 40b132
{
Packit 40b132
    PLArenaPool           *poolp;
Packit 40b132
    void                  *mark;
Packit 40b132
    CRMFPOPOPrivKey       *popoPrivKey;
Packit 40b132
    CRMFProofOfPossession *pop;
Packit 40b132
    SECStatus              rv;
Packit 40b132
Packit 40b132
    PORT_Assert(inCertReqMsg != NULL && encPrivKey != NULL);
Packit 40b132
    poolp = inCertReqMsg->poolp;
Packit 40b132
    mark = PORT_ArenaMark(poolp);
Packit 40b132
    pop = PORT_ArenaZNew(poolp, CRMFProofOfPossession);
Packit 40b132
    if (pop == NULL) {
Packit 40b132
        goto loser;
Packit 40b132
    }
Packit 40b132
    pop->popUsed = inChoice;
Packit 40b132
    /* popChoice is a union, so getting a pointer to one
Packit 40b132
     * field gives me a pointer to the other fields as
Packit 40b132
     * well.  This in essence points to both 
Packit 40b132
     * pop->popChoice.keyEncipherment and
Packit 40b132
     * pop->popChoice.keyAgreement
Packit 40b132
     */
Packit 40b132
    popoPrivKey = &pop->popChoice.keyEncipherment;
Packit 40b132
Packit 40b132
    rv = SECITEM_CopyItem(poolp, &(popoPrivKey->message.thisMessage),
Packit 40b132
			  encPrivKey);
Packit 40b132
    if (rv != SECSuccess) {
Packit 40b132
        goto loser;
Packit 40b132
    }
Packit 40b132
    popoPrivKey->message.thisMessage.len <<= 3;
Packit 40b132
    popoPrivKey->messageChoice = crmfThisMessage;
Packit 40b132
    inCertReqMsg->pop = pop;
Packit 40b132
    rv = crmf_encode_popoprivkey(poolp, inCertReqMsg, popoPrivKey,
Packit 40b132
				 crmf_get_template_for_privkey(inChoice));
Packit 40b132
    if (rv != SECSuccess) {
Packit 40b132
        goto loser;
Packit 40b132
    }
Packit 40b132
    PORT_ArenaUnmark(poolp, mark);
Packit 40b132
    return SECSuccess;
Packit 40b132
    
Packit 40b132
 loser:
Packit 40b132
    PORT_ArenaRelease(poolp, mark);
Packit 40b132
    return SECFailure;
Packit 40b132
}
Packit 40b132
Packit 40b132
static SECStatus
Packit 40b132
crmf_add_privkey_dhmac(CRMFCertReqMsg *inCertReqMsg, SECItem *dhmac,
Packit 40b132
                             CRMFPOPChoice inChoice)
Packit 40b132
{
Packit 40b132
    PLArenaPool           *poolp;
Packit 40b132
    void                  *mark;
Packit 40b132
    CRMFPOPOPrivKey       *popoPrivKey;
Packit 40b132
    CRMFProofOfPossession *pop;
Packit 40b132
    SECStatus              rv;
Packit 40b132
Packit 40b132
    PORT_Assert(inCertReqMsg != NULL && dhmac != NULL);
Packit 40b132
    poolp = inCertReqMsg->poolp;
Packit 40b132
    mark = PORT_ArenaMark(poolp);
Packit 40b132
    pop = PORT_ArenaZNew(poolp, CRMFProofOfPossession);
Packit 40b132
    if (pop == NULL) {
Packit 40b132
        goto loser;
Packit 40b132
    }
Packit 40b132
    pop->popUsed = inChoice;
Packit 40b132
    popoPrivKey = &pop->popChoice.keyAgreement;
Packit 40b132
Packit 40b132
    rv = SECITEM_CopyItem(poolp, &(popoPrivKey->message.dhMAC),
Packit 40b132
                          dhmac);
Packit 40b132
    if (rv != SECSuccess) {
Packit 40b132
        goto loser;
Packit 40b132
    }
Packit 40b132
    popoPrivKey->message.dhMAC.len <<= 3;
Packit 40b132
    popoPrivKey->messageChoice = crmfDHMAC;
Packit 40b132
    inCertReqMsg->pop = pop;
Packit 40b132
    rv = crmf_encode_popoprivkey(poolp, inCertReqMsg, popoPrivKey,
Packit 40b132
                                 crmf_get_template_for_privkey(inChoice));
Packit 40b132
    if (rv != SECSuccess) {
Packit 40b132
        goto loser;
Packit 40b132
    }
Packit 40b132
    PORT_ArenaUnmark(poolp, mark);
Packit 40b132
    return SECSuccess;
Packit 40b132
    
Packit 40b132
 loser:
Packit 40b132
    PORT_ArenaRelease(poolp, mark);
Packit 40b132
    return SECFailure;
Packit 40b132
}
Packit 40b132
Packit 40b132
static SECStatus
Packit 40b132
crmf_add_privkey_subseqmessage(CRMFCertReqMsg        *inCertReqMsg,
Packit 40b132
			       CRMFSubseqMessOptions  subsequentMessage,
Packit 40b132
			       CRMFPOPChoice          inChoice)
Packit 40b132
{
Packit 40b132
    void                  *mark;
Packit 40b132
    PLArenaPool           *poolp;
Packit 40b132
    CRMFProofOfPossession *pop;
Packit 40b132
    CRMFPOPOPrivKey       *popoPrivKey;
Packit 40b132
    SECStatus              rv;
Packit 40b132
    const SEC_ASN1Template *privKeyTemplate;
Packit 40b132
Packit 40b132
    if (subsequentMessage == crmfNoSubseqMess) {
Packit 40b132
        return SECFailure;
Packit 40b132
    }
Packit 40b132
    poolp = inCertReqMsg->poolp;
Packit 40b132
    mark = PORT_ArenaMark(poolp);
Packit 40b132
    pop = PORT_ArenaZNew(poolp, CRMFProofOfPossession);
Packit 40b132
    if (pop == NULL) {
Packit 40b132
        goto loser;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    pop->popUsed = inChoice;
Packit 40b132
    /* 
Packit 40b132
     * We have a union, so a pointer to one member of the union
Packit 40b132
     * is also a member to another member of that same union.
Packit 40b132
     */
Packit 40b132
    popoPrivKey = &pop->popChoice.keyEncipherment;
Packit 40b132
Packit 40b132
    switch (subsequentMessage) {
Packit 40b132
    case crmfEncrCert:
Packit 40b132
        rv = crmf_encode_integer(poolp, 
Packit 40b132
				 &(popoPrivKey->message.subsequentMessage),
Packit 40b132
				 0);
Packit 40b132
	break;
Packit 40b132
    case crmfChallengeResp:
Packit 40b132
        rv = crmf_encode_integer(poolp,
Packit 40b132
				 &(popoPrivKey->message.subsequentMessage),
Packit 40b132
				 1);
Packit 40b132
	break;
Packit 40b132
    default:
Packit 40b132
        goto loser;
Packit 40b132
    }
Packit 40b132
    if (rv != SECSuccess) {
Packit 40b132
        goto loser;
Packit 40b132
    }
Packit 40b132
    popoPrivKey->messageChoice = crmfSubsequentMessage;
Packit 40b132
    privKeyTemplate = crmf_get_template_for_privkey(inChoice);
Packit 40b132
    inCertReqMsg->pop = pop;
Packit 40b132
    rv = crmf_encode_popoprivkey(poolp, inCertReqMsg, popoPrivKey,
Packit 40b132
				 privKeyTemplate);
Packit 40b132
Packit 40b132
    if (rv != SECSuccess) {
Packit 40b132
        goto loser;
Packit 40b132
    }
Packit 40b132
    PORT_ArenaUnmark(poolp, mark);
Packit 40b132
    return SECSuccess;
Packit 40b132
 loser:
Packit 40b132
    PORT_ArenaRelease(poolp, mark);
Packit 40b132
    return SECFailure;
Packit 40b132
}
Packit 40b132
Packit 40b132
SECStatus 
Packit 40b132
CRMF_CertReqMsgSetKeyEnciphermentPOP(CRMFCertReqMsg        *inCertReqMsg,
Packit 40b132
				     CRMFPOPOPrivKeyChoice  inKeyChoice,
Packit 40b132
				     CRMFSubseqMessOptions  subseqMess,
Packit 40b132
				     SECItem               *encPrivKey)
Packit 40b132
{
Packit 40b132
    SECStatus rv;
Packit 40b132
Packit 40b132
    PORT_Assert(inCertReqMsg != NULL && inCertReqMsg->pop == NULL);
Packit 40b132
    if (CRMF_CertReqMsgGetPOPType(inCertReqMsg) != crmfNoPOPChoice) {
Packit 40b132
        return SECFailure;
Packit 40b132
    }
Packit 40b132
    switch (inKeyChoice) {    
Packit 40b132
    case crmfThisMessage:
Packit 40b132
        rv = crmf_add_privkey_thismessage(inCertReqMsg, encPrivKey,
Packit 40b132
					  crmfKeyEncipherment);
Packit 40b132
	break;
Packit 40b132
    case crmfSubsequentMessage:
Packit 40b132
        rv = crmf_add_privkey_subseqmessage(inCertReqMsg, subseqMess, 
Packit 40b132
					    crmfKeyEncipherment);
Packit 40b132
        break;
Packit 40b132
    case crmfDHMAC:
Packit 40b132
    default:
Packit 40b132
        rv = SECFailure;
Packit 40b132
    }
Packit 40b132
    return rv;
Packit 40b132
}
Packit 40b132
Packit 40b132
SECStatus 
Packit 40b132
CRMF_CertReqMsgSetKeyAgreementPOP (CRMFCertReqMsg        *inCertReqMsg,
Packit 40b132
				   CRMFPOPOPrivKeyChoice  inKeyChoice,
Packit 40b132
				   CRMFSubseqMessOptions  subseqMess,
Packit 40b132
				   SECItem               *encPrivKey)
Packit 40b132
{
Packit 40b132
    SECStatus rv;
Packit 40b132
Packit 40b132
    PORT_Assert(inCertReqMsg != NULL && inCertReqMsg->pop == NULL);
Packit 40b132
    switch (inKeyChoice) {    
Packit 40b132
    case crmfThisMessage:
Packit 40b132
        rv = crmf_add_privkey_thismessage(inCertReqMsg, encPrivKey,
Packit 40b132
					  crmfKeyAgreement);
Packit 40b132
	break;
Packit 40b132
    case crmfSubsequentMessage:
Packit 40b132
        rv = crmf_add_privkey_subseqmessage(inCertReqMsg, subseqMess, 
Packit 40b132
					    crmfKeyAgreement);
Packit 40b132
	break;
Packit 40b132
    case crmfDHMAC:
Packit 40b132
        /* In this case encPrivKey should be the calculated dhMac
Packit 40b132
         * as specified in RFC 2511 */
Packit 40b132
        rv = crmf_add_privkey_dhmac(inCertReqMsg, encPrivKey,
Packit 40b132
                                    crmfKeyAgreement);
Packit 40b132
        break;
Packit 40b132
    default:
Packit 40b132
        rv = SECFailure;
Packit 40b132
    }
Packit 40b132
    return rv;
Packit 40b132
}
Packit 40b132