crmfres.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:41k
- /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
- /*
- * 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.
- */
- /* Cartman Server specific includes */
- #include "serv.h"
- #include "crmfres.h"
- #include "kgenctxt.h"
- #include "p12res.h"
- #include "newproto.h"
- #include "messages.h"
- #include "certres.h"
- #include "oldfunc.h"
- /* NSS include files */
- #include "base64.h"
- #include "crmfi.h"
- #include "cmmfi.h"
- #include "cert.h"
- #include "secmod.h"
- #include "secasn1.h"
- /*
- * These defines are used for setting the keyUsage extensions in
- * the requests.
- */
- #define DIGITAL_SIGNATURE KU_DIGITAL_SIGNATURE
- #define NON_REPUDIATION KU_NON_REPUDIATION
- #define KEY_ENCIPHERMENT KU_KEY_ENCIPHERMENT
- #define KEY_AGREEMENT KU_KEY_AGREEMENT
- /* I can use this for both SSMKeyPair and SSMCRMFRequest because they
- * both inherit directly from SSMResource
- *
- * A simple macro for an object that inherits from SSMResource that will
- * convert the object pointer into a SSMResource pointer.
- */
- #define SSMRESOURCE(object) (&(object)->super)
- /*
- * This structure is used for callbacks passed to the ASN1 encoder.
- */
- typedef struct CRMFASN1ArgStr {
- SECItem buffer;
- long allocatedLen;
- } CRMFASN1Arg;
- /*
- * Default allocation size for a DER chunk that will be passed to the
- * ASN1 parser.
- */
- #define DEFAULT_ASN1_CHUNK_SIZE 1024
- typedef struct CMMFResponseArgStr {
- SECItem *msg;
- SSMControlConnection *connection;
- } CMMFResponseArg;
- /* Forward decls */
- void
- SSMCRMFRequest_PrepareBitStringForEncoding (SECItem *bitsmap, SECItem *value);
- SSMStatus
- SSMCRMFRequest_SetKeyUsageExtension(SSMCRMFRequest *crmfReq,
- unsigned char keyUsage);
- SSMStatus
- SSMCRMFRequest_SetRSADualUse(SSMCRMFRequest *crmfReq);
- SSMStatus
- SSMCRMFRequest_SetRSAKeyEx(SSMCRMFRequest *crmfReq);
- SSMStatus
- SSMCRMFRequest_SetRSASign(SSMCRMFRequest *crmfReq);
- SSMStatus
- SSMCRMFRequest_SetRSANonRepudiation(SSMCRMFRequest *crmfReq);
- SSMStatus
- SSMCRMFRequest_SetRSASignNonRepudiation(SSMCRMFRequest *crmfReq);
- SSMStatus
- SSMCRMFRequest_SetDH(SSMCRMFRequest *crmfReq);
- SSMStatus
- SSMCRMFRequest_SetDSASign(SSMCRMFRequest *crmfReq);
- SSMStatus
- SSMCRMFRequest_SetDSANonRepudiation(SSMCRMFRequest *crmfReq);
- SSMStatus
- SSMCRMFRequest_SetDSASignNonRepudiation(SSMCRMFRequest *crmfReq);
- SSMStatus
- SSMCRMFRequest_SetKeyGenType(SSMCRMFRequest *crmfReq, SSMKeyGenType keyGenType);
- SSMStatus
- SSMCRMFRequest_SetDN(SSMCRMFRequest *crmfReq,
- char *data);
- SSMStatus
- SSMCRMFRequest_SetRegToken(SSMCRMFRequest *crmfReq,
- char *value);
- SSMStatus
- SSMCRMFRequest_SetAuthenticator(SSMCRMFRequest *crmfReq,
- char *value);
- PRBool
- SSMCRMFRequest_HasEscrowAuthority(SSMCRMFRequest *currReq);
- SSMStatus
- SSMCRMFRequest_SetKeyEnciphermentPOP(CRMFCertReqMsg *certReqMsg,
- SSMCRMFRequest *curReq);
- SSMStatus
- SSMCRMFRequest_SetProofOfPossession(CRMFCertReqMsg *certReqMsg,
- SSMCRMFRequest *curReq);
- SECKEYPrivateKey*
- SSM_FindPrivKeyFromKeyID(SECItem *keyID, SECMODModule *currMod,
- SSMControlConnection *ctrl);
- SECKEYPrivateKey*
- SSM_FindPrivKeyFromPubValue(SECItem *publicValue, SECMODModuleList *modList,
- SSMControlConnection *ctrl);
- SSMStatus
- SSM_InitCRMFASN1Arg(CRMFASN1Arg *arg);
- void
- SSM_GenericASN1Callback(void *arg, const char *buf, unsigned long len);
- SSMStatus
- SSM_CreateNewCRMFRequest(SECItem *msg, SSMControlConnection *connection,
- SSMResourceID *destID)
- {
- SSMStatus prv;
- SSMResource *keyPairRes=NULL, *crmfReqRes=NULL;
- SSMCRMFRequestArg arg;
- SingleNumMessage request;
- if (CMT_DecodeMessage(SingleNumMessageTemplate, &request, (CMTItem*)msg) != CMTSuccess) {
- goto loser;
- }
- prv = SSMControlConnection_GetResource(connection, (SSMResourceID)request.value,
- &keyPairRes);
- if (prv != PR_SUCCESS || keyPairRes == NULL) {
- goto loser;
- }
- if (!SSM_IsAKindOf(keyPairRes, SSM_RESTYPE_KEY_PAIR)) {
- goto loser;
- }
- arg.keyPair = (SSMKeyPair*)keyPairRes;
- arg.connection = connection;
- prv = SSM_CreateResource(SSM_RESTYPE_CRMF_REQUEST, (void*)&arg, connection,
- destID, &crmfReqRes);
- if (prv != PR_SUCCESS || crmfReqRes == NULL) {
- goto loser;
- }
- SSM_FreeResource(keyPairRes);
- crmfReqRes->m_clientCount++;
- return PR_SUCCESS;
- loser:
- if (keyPairRes != NULL) {
- SSM_FreeResource(keyPairRes);
- }
- if (crmfReqRes != NULL) {
- SSM_FreeResource(crmfReqRes);
- }
- return PR_FAILURE;
- }
- SSMStatus
- SSMCRMFRequest_Create(void *arg, SSMControlConnection * connection,
- SSMResource **res)
- {
- SSMCRMFRequest *crmfReq;
- SSMStatus rv;
- SSMCRMFRequestArg *createArg = (SSMCRMFRequestArg*)arg;
- crmfReq = SSM_ZNEW(SSMCRMFRequest);
- if (crmfReq == NULL) {
- goto loser;
- }
- rv = SSMCRMFRequest_Init(crmfReq, connection, SSM_RESTYPE_CRMF_REQUEST,
- createArg->keyPair, createArg->connection);
-
- if (rv != PR_SUCCESS) {
- goto loser;
- }
- *res = SSMRESOURCE(crmfReq);
- return PR_SUCCESS;
-
- loser:
- if (crmfReq != NULL) {
- SSM_FreeResource(SSMRESOURCE(crmfReq));
- }
- *res = NULL;
- return PR_FAILURE;
- }
- SSMStatus
- SSMCRMFRequest_Init(SSMCRMFRequest *inCRMFReq,
- SSMControlConnection * conn,
- SSMResourceType type,
- SSMKeyPair *inKeyPair,
- SSMControlConnection *inConnection)
- {
- CRMFCertRequest *certReq = NULL;
- CERTSubjectPublicKeyInfo *spki = NULL;
- SSMStatus rv;
- SECStatus srv;
- long version = SEC_CERTIFICATE_VERSION_3 ;
- /* Version passed in is the value
- * to be encoded for the version
- * of the certificate.
- */
- if (inKeyPair == NULL || inConnection == NULL) {
- goto loser;
- }
- rv = SSMResource_Init(conn, SSMRESOURCE(inCRMFReq), type);
- if (rv != PR_SUCCESS) {
- goto loser;
- }
- /* This reference will be inherited by the SSMCRMFRequest
- * structure being initialized.
- */
- SSM_GetResourceReference(SSMRESOURCE(inKeyPair));
- if (inKeyPair->m_PubKey == NULL ||
- inKeyPair->m_PrivKey == NULL) {
- goto loser;
- }
- inCRMFReq->m_KeyPair = inKeyPair;
- inCRMFReq->m_KeyGenType = invalidKeyGen;
- inCRMFReq->m_Connection = inConnection;
- /* How do I remember that request number? */
- certReq = CRMF_CreateCertRequest(rand());
- if (certReq == NULL) {
- goto loser;
- }
- srv = CRMF_CertRequestSetTemplateField(certReq, crmfVersion, &version);
- if (srv != SECSuccess) {
- goto loser;
- }
- spki = SECKEY_CreateSubjectPublicKeyInfo(inKeyPair->m_PubKey);
- if(spki == NULL) {
- goto loser;
- }
- srv = CRMF_CertRequestSetTemplateField(certReq, crmfPublicKey, spki);
- SECKEY_DestroySubjectPublicKeyInfo(spki);
- if (srv != SECSuccess) {
- goto loser;
- }
- inCRMFReq->m_CRMFRequest = certReq;
- if (inKeyPair->m_KeyGenContext->m_eaCert != NULL &&
- inKeyPair->m_KeyGenType == rsaEnc) {
- rv = SSMCRMFRequest_SetEscrowAuthority(inCRMFReq,
- inKeyPair->m_KeyGenContext->m_eaCert);
- if (rv != PR_SUCCESS) {
- goto loser;
- }
- }
- return PR_SUCCESS;
- loser:
- /* We only obtain a reference to the key pair in this function, so
- * that's the only reference we need to free in here.
- */
- if (inKeyPair != NULL) {
- SSM_FreeResource(SSMRESOURCE(inKeyPair));
- }
- if (certReq != NULL) {
- CRMF_DestroyCertRequest(certReq);
- }
- return PR_FAILURE;
- }
- SSMStatus
- SSMCRMFRequest_Destroy(SSMResource *inRequest, PRBool doFree)
- {
- SSMCRMFRequest *crmfReq = (SSMCRMFRequest*)inRequest;
- if (crmfReq->m_KeyPair != NULL) {
- SSM_FreeResource(SSMRESOURCE(crmfReq->m_KeyPair));
- crmfReq->m_KeyPair = NULL;
- }
- if (crmfReq->m_CRMFRequest != NULL) {
- CRMF_DestroyCertRequest(crmfReq->m_CRMFRequest);
- crmfReq->m_CRMFRequest = NULL;
- }
- SSMResource_Destroy(SSMRESOURCE(crmfReq), PR_FALSE);
- if (doFree) {
- PR_Free(crmfReq);
- }
- return PR_SUCCESS;
- }
- void
- SSMCRMFRequest_PrepareBitStringForEncoding (SECItem *bitsmap, SECItem *value)
- {
- unsigned char onebyte;
- unsigned int i, len = 0;
- /* to prevent warning on some platform at compile time */
- onebyte = ' ';
- /* Get the position of the right-most turn-on bit */
- for (i = 0; i < (value->len ) * 8; ++i) {
- if (i % 8 == 0)
- onebyte = value->data[i/8];
- if (onebyte & 0x80)
- len = i;
- onebyte <<= 1;
- }
- bitsmap->data = value->data;
- /* Add one here since we work with base 1 */
- bitsmap->len = len + 1;
- }
- /*
- * Below is the set of functions that set the keyUsage extension in the
- * request. Each different type of key generation has a different
- * value that gets set for keyUsage. So each one defines the
- * value and just calls SSMCRMFRequest_SetKeyUsageExtension.
- */
- SSMStatus
- SSMCRMFRequest_SetKeyUsageExtension(SSMCRMFRequest *crmfReq,
- unsigned char keyUsage)
- {
- SECItem *encodedExt= NULL;
- SECItem keyUsageValue = { (SECItemType) 0, NULL, 0 };
- SECItem bitsmap = { (SECItemType) 0, NULL, 0 };
- SECStatus srv;
- CRMFCertExtension *ext = NULL;
- CRMFCertExtCreationInfo extAddParams;
- SEC_ASN1Template bitStrTemplate = {SEC_ASN1_BIT_STRING, 0, NULL,
- sizeof(SECItem)};
- keyUsageValue.data = &keyUsage;
- keyUsageValue.len = 1;
- SSMCRMFRequest_PrepareBitStringForEncoding(&bitsmap, &keyUsageValue);
- encodedExt = SEC_ASN1EncodeItem(NULL, NULL, &bitsmap,&bitStrTemplate);
- if (encodedExt == NULL) {
- goto loser;
- }
- ext = CRMF_CreateCertExtension(SEC_OID_X509_KEY_USAGE, PR_TRUE, encodedExt);
- if (ext == NULL) {
- goto loser;
- }
- extAddParams.numExtensions = 1;
- extAddParams.extensions = &ext;
- srv = CRMF_CertRequestSetTemplateField(crmfReq->m_CRMFRequest, crmfExtension,
- &extAddParams);
- CRMF_DestroyCertExtension(ext);
- if (srv != SECSuccess) {
- goto loser;
- }
- return PR_SUCCESS;
- loser:
- if (encodedExt != NULL) {
- SECITEM_FreeItem(encodedExt, PR_TRUE);
- }
- return PR_FAILURE;
- }
- SSMStatus
- SSMCRMFRequest_SetRSADualUse(SSMCRMFRequest *crmfReq)
- {
- unsigned char keyUsage = DIGITAL_SIGNATURE
- | NON_REPUDIATION
- | KEY_ENCIPHERMENT;
- crmfReq->m_KeyGenType = rsaDualUse;
- return SSMCRMFRequest_SetKeyUsageExtension(crmfReq, keyUsage);
- }
- SSMStatus
- SSMCRMFRequest_SetRSAKeyEx(SSMCRMFRequest *crmfReq)
- {
- unsigned char keyUsage = KEY_ENCIPHERMENT;
-
- crmfReq->m_KeyGenType = rsaEnc;
- return SSMCRMFRequest_SetKeyUsageExtension(crmfReq, keyUsage);
- }
- SSMStatus
- SSMCRMFRequest_SetRSASign(SSMCRMFRequest *crmfReq)
- {
- unsigned char keyUsage = DIGITAL_SIGNATURE;
-
- crmfReq->m_KeyGenType = rsaSign;
- return SSMCRMFRequest_SetKeyUsageExtension(crmfReq, keyUsage);
- }
- SSMStatus
- SSMCRMFRequest_SetRSANonRepudiation(SSMCRMFRequest *crmfReq)
- {
- unsigned char keyUsage = NON_REPUDIATION;
- crmfReq->m_KeyGenType = rsaNonrepudiation;
- return SSMCRMFRequest_SetKeyUsageExtension(crmfReq, keyUsage);
- }
- SSMStatus
- SSMCRMFRequest_SetRSASignNonRepudiation(SSMCRMFRequest *crmfReq)
- {
- unsigned char keyUsage = DIGITAL_SIGNATURE |
- NON_REPUDIATION;
- crmfReq->m_KeyGenType = rsaSignNonrepudiation;
- return SSMCRMFRequest_SetKeyUsageExtension(crmfReq, keyUsage);
- }
- SSMStatus
- SSMCRMFRequest_SetDH(SSMCRMFRequest *crmfReq)
- {
- unsigned char keyUsage = KEY_AGREEMENT;
-
- crmfReq->m_KeyGenType = dhEx;
- return SSMCRMFRequest_SetKeyUsageExtension(crmfReq, keyUsage);
- }
- SSMStatus
- SSMCRMFRequest_SetDSASign(SSMCRMFRequest *crmfReq)
- {
- unsigned char keyUsage = DIGITAL_SIGNATURE;
- crmfReq->m_KeyGenType = dsaSign;
- return SSMCRMFRequest_SetKeyUsageExtension(crmfReq, keyUsage);
- }
- SSMStatus
- SSMCRMFRequest_SetDSANonRepudiation(SSMCRMFRequest *crmfReq)
- {
- unsigned char keyUsage = NON_REPUDIATION;
- crmfReq->m_KeyGenType = dsaNonrepudiation;
- return SSMCRMFRequest_SetKeyUsageExtension(crmfReq, keyUsage);
- }
- SSMStatus
- SSMCRMFRequest_SetDSASignNonRepudiation(SSMCRMFRequest *crmfReq)
- {
- unsigned char keyUsage = DIGITAL_SIGNATURE |
- NON_REPUDIATION;
- crmfReq->m_KeyGenType = dsaSignNonrepudiation;
- return SSMCRMFRequest_SetKeyUsageExtension(crmfReq, keyUsage);
- }
- SSMStatus
- SSMCRMFRequest_SetKeyGenType(SSMCRMFRequest *crmfReq, SSMKeyGenType keyGenType)
- {
- SSMStatus rv;
- if (crmfReq->m_KeyGenType != invalidKeyGen) {
- return PR_FAILURE;
- }
- switch (keyGenType) {
- case rsaDualUse:
- rv = SSMCRMFRequest_SetRSADualUse(crmfReq);
- break;
- case rsaEnc:
- rv = SSMCRMFRequest_SetRSAKeyEx(crmfReq);
- break;
- case rsaSign:
- rv = SSMCRMFRequest_SetRSASign(crmfReq);
- break;
- case rsaNonrepudiation:
- rv = SSMCRMFRequest_SetRSANonRepudiation(crmfReq);
- break;
- case rsaSignNonrepudiation:
- rv = SSMCRMFRequest_SetRSASignNonRepudiation(crmfReq);
- break;
- case dhEx:
- rv = SSMCRMFRequest_SetDH(crmfReq);
- break;
- case dsaSign:
- rv = SSMCRMFRequest_SetDSASign(crmfReq);
- break;
- case dsaNonrepudiation:
- rv = SSMCRMFRequest_SetDSANonRepudiation(crmfReq);
- break;
- case dsaSignNonrepudiation:
- rv = SSMCRMFRequest_SetDSASignNonRepudiation(crmfReq);
- break;
- default:
- SSM_DEBUG("Unknown KeyGenType %dn", keyGenType);
- rv = PR_FAILURE;
- break;
- }
- return rv;
- }
- /*
- * This function takes an ASCII string in RFC1485 format and converts it
- * to a CERTName, then sets that names as the subjectName for the request
- * passed in.
- */
- SSMStatus
- SSMCRMFRequest_SetDN(SSMCRMFRequest *crmfReq,
- char *data)
- {
- SECStatus srv;
- CERTName *subjectName;
- if (data == NULL || CRMF_CertRequestIsFieldPresent(crmfReq->m_CRMFRequest,
- crmfSubject)) {
- return PR_FAILURE;
- }
- subjectName = CERT_AsciiToName(data);
- if (subjectName == NULL) {
- return PR_FAILURE;
- }
- srv = CRMF_CertRequestSetTemplateField (crmfReq->m_CRMFRequest, crmfSubject,
- (void*)subjectName);
- CERT_DestroyName(subjectName);
- return (srv == SECSuccess) ? PR_SUCCESS : PR_FAILURE;
- }
- /*
- * This function will set the Registration Token Control in
- * the certificate request passed in. We only allow one registration
- * token control per request in Cartman.
- */
- SSMStatus
- SSMCRMFRequest_SetRegToken(SSMCRMFRequest *crmfReq,
- char *value)
- {
- SECItem src, *derEncoded;
- SECStatus rv;
- if (CRMF_CertRequestIsControlPresent(crmfReq->m_CRMFRequest,
- crmfRegTokenControl)) {
- return PR_FAILURE;
- }
- src.data = (unsigned char*)value;
- src.len = strlen(value)+1;
- derEncoded = SEC_ASN1EncodeItem(NULL, NULL, &src, SEC_UTF8StringTemplate);
- if (derEncoded == NULL) {
- return PR_FAILURE;
- }
- rv = CRMF_CertRequestSetRegTokenControl(crmfReq->m_CRMFRequest, derEncoded);
- SECITEM_FreeItem(derEncoded, PR_TRUE);
- if (rv != SECSuccess) {
- return PR_FAILURE;
- }
- return PR_SUCCESS;
- }
- /*
- * This function sets the authenticator control in the certificate request.
- * The string passed in is an ASCII string. The CRMF libraries encode that
- * string as a UTF8 string and then include it in the request. Cartman will
- * only allow one Authenticator control per request.
- */
- SSMStatus
- SSMCRMFRequest_SetAuthenticator(SSMCRMFRequest *crmfReq,
- char *value)
- {
- SECItem src, *derEncoded;
- SECStatus rv;
- if (CRMF_CertRequestIsControlPresent(crmfReq->m_CRMFRequest,
- crmfAuthenticatorControl)) {
- return PR_FAILURE;
- }
- src.data = (unsigned char*)value;
- src.len = strlen(value)+1;
- derEncoded = SEC_ASN1EncodeItem(NULL, NULL, &src, SEC_UTF8StringTemplate);
- if (derEncoded == NULL) {
- return PR_FAILURE;
- }
- rv = CRMF_CertRequestSetAuthenticatorControl(crmfReq->m_CRMFRequest,
- derEncoded);
- SECITEM_FreeItem(derEncoded, PR_TRUE);
- if (rv != SECSuccess) {
- return PR_FAILURE;
- }
- return PR_SUCCESS;
- }
- SSMStatus
- SSMCRMFRequest_SetEscrowAuthority(SSMCRMFRequest *crmfReq,
- CERTCertificate *eaCert)
- {
- CRMFEncryptedKey *encrKey = NULL;
- CRMFPKIArchiveOptions *archOpt = NULL;
- SECStatus rv;
- PR_ASSERT(eaCert!= NULL);
- if (eaCert == NULL ||
- CRMF_CertRequestIsControlPresent(crmfReq->m_CRMFRequest,
- crmfPKIArchiveOptionsControl)) {
- return PR_FAILURE;
- }
- /*
- * CRMF_CreatePKIArchiveOptions checks to see if the value passed in,
- * in this case encrKey, is NULL. So passing in the value without
- * checking the contents first is OK in this case. Really.
- */
- encrKey =
- CRMF_CreateEncryptedKeyWithEncryptedValue(crmfReq->m_KeyPair->m_PrivKey,
- eaCert);
- archOpt = CRMF_CreatePKIArchiveOptions(crmfEncryptedPrivateKey,
- (void*)encrKey);
- if (archOpt == NULL) {
- goto loser;
- }
- rv = CRMF_CertRequestSetPKIArchiveOptions(crmfReq->m_CRMFRequest, archOpt);
- if (rv != SECSuccess) {
- goto loser;
- }
- CRMF_DestroyEncryptedKey(encrKey);
- CRMF_DestroyPKIArchiveOptions(archOpt);
- return PR_SUCCESS;
- loser:
- /* Free up all the memory here. */
- if (encrKey != NULL) {
- CRMF_DestroyEncryptedKey(encrKey);
- }
- if (archOpt != NULL) {
- CRMF_DestroyPKIArchiveOptions(archOpt);
- }
- return PR_FAILURE;
- }
- SSMStatus
- SSMCRMFRequest_SetAttr(SSMResource *res,
- SSMAttributeID attrID,
- SSMAttributeValue *value)
- {
- SSMCRMFRequest *crmfReq = (SSMCRMFRequest*)res;
- SSMStatus rv;
- SSM_DEBUG("Calling SSMCRMFRequest_SetAttrn");
- switch (attrID) {
- case SSM_FID_CRMFREQ_KEY_TYPE:
- SSM_DEBUG("Setting SSMKeyGenType to %dn", value->u.numeric);
- if (value->type != SSM_NUMERIC_ATTRIBUTE) {
- rv = PR_FAILURE;
- break;
- }
- rv = SSMCRMFRequest_SetKeyGenType(crmfReq, (SSMKeyGenType) value->u.numeric);
- break;
- case SSM_FID_CRMFREQ_DN:
- SSM_DEBUG("Setting the DN to %sn", value->u.string.data);
- if (value->type != SSM_STRING_ATTRIBUTE) {
- rv = PR_FAILURE;
- break;
- }
- rv = SSMCRMFRequest_SetDN(crmfReq, (char *) value->u.string.data);
- break;
- case SSM_FID_CRMFREQ_REGTOKEN:
- SSM_DEBUG("Setting the regToken to %sn", value->u.string.data);
- if (value->type != SSM_STRING_ATTRIBUTE) {
- rv = PR_FAILURE;
- break;
- }
- rv = SSMCRMFRequest_SetRegToken(crmfReq, (char *) value->u.string.data);
- break;
- case SSM_FID_CRMFREQ_AUTHENTICATOR:
- SSM_DEBUG("Setting the authenticator to %sn", value->u.string.data);
- rv = SSMCRMFRequest_SetAuthenticator(crmfReq, (char *) value->u.string.data);
- break;
- default:
- SSM_DEBUG("Got unknown CRMF Set Attribute request %dn", attrID);
- rv = PR_FAILURE;
- break;
- }
- return rv;
- }
- /*
- * This function checks to see if a CRMF request has the PKIArchiveOptions
- * control already set.
- */
- PRBool
- SSMCRMFRequest_HasEscrowAuthority(SSMCRMFRequest *currReq)
- {
- return CRMF_CertRequestIsControlPresent(currReq->m_CRMFRequest,
- crmfPKIArchiveOptionsControl);
- }
- /*
- * This function will set the Proof Of Possession (POP) for a request
- * associated with a key pair intended to do Key Encipherment. Currently
- * this means encryption only keys.
- */
- SSMStatus
- SSMCRMFRequest_SetKeyEnciphermentPOP(CRMFCertReqMsg *certReqMsg,
- SSMCRMFRequest *curReq)
- {
- SECItem bitString;
- unsigned char der[2];
- SECStatus rv;
- if (SSMCRMFRequest_HasEscrowAuthority(curReq)) {
- /* For proof of possession on escrowed keys, we use the
- * this Message option of POPOPrivKey and include a zero
- * length bit string in the POP field. This is OK because the encrypted
- * private key already exists as part of the PKIArchiveOptions
- * Control and that for all intents and purposes proves that
- * we do own the private key.
- */
- der[0] = 0x03; /*We've got a bit string */
- der[1] = 0x00; /*We've got a 0 length bit string */
- bitString.data = der;
- bitString.len = 2;
- rv = CRMF_CertReqMsgSetKeyEnciphermentPOP(certReqMsg, crmfThisMessage,
- crmfNoSubseqMess, &bitString);
- } else {
- /* If the encryption key is not being escrowed, then we set the
- * Proof Of Possession to be a Challenge Response mechanism.
- */
- rv = CRMF_CertReqMsgSetKeyEnciphermentPOP(certReqMsg,
- crmfSubsequentMessage,
- crmfChallengeResp, NULL);
- }
- return (rv == SECSuccess) ? PR_SUCCESS : PR_FAILURE;
- }
- /*
- * This function sets the Proof Of Possession(POP) for a requests.
- * All requests except for those associated with encryption only keys
- * sign the request as their form of POP. Encryption only keys require
- * extra logic in determining the type of POP to use, that is why encryption
- * only keys have an extra layer for setting the POP instead of calling into
- * the CRMF libraries directly from within this function.
- */
- SSMStatus
- SSMCRMFRequest_SetProofOfPossession(CRMFCertReqMsg *certReqMsg,
- SSMCRMFRequest *curReq)
- {
- SSMStatus rv;
- SECStatus srv;
- switch (curReq->m_KeyGenType) {
- case rsaSign:
- case rsaDualUse:
- case rsaNonrepudiation:
- case rsaSignNonrepudiation:
- case dsaSign:
- case dsaNonrepudiation:
- case dsaSignNonrepudiation:
- srv = CRMF_CertReqMsgSetSignaturePOP(certReqMsg,
- curReq->m_KeyPair->m_PrivKey,
- curReq->m_KeyPair->m_PubKey, NULL,
- NULL, NULL);
- rv = (srv == SECSuccess) ? PR_SUCCESS : PR_FAILURE;
- break;
- case rsaEnc:
- rv = SSMCRMFRequest_SetKeyEnciphermentPOP(certReqMsg, curReq);
- break;
- case dhEx:
- /* This case may be supported in the future, but for now, we just fall
- * though to the default case and return an error for diffie-hellman keys.
- */
- default:
- rv = PR_FAILURE;
- break;
- }
- return rv;
- }
- SSMStatus
- SSM_EncodeCRMFRequests(SSMControlConnection * ctrl,SECItem *msg,
- char **destDER, SSMPRUint32 *destLen)
- {
- PRInt32 i;
- SSMStatus rv;
- SECStatus srv;
- CRMFCertReqMsg **certReqMsgs = NULL;
- SSMCRMFRequest *curReq;
- SSMResource *res;
- SECItem *encodedReq;
- CRMFCertReqMessages messages;
- EncodeCRMFReqRequest request;
- if (CMT_DecodeMessage(EncodeCRMFReqRequestTemplate, &request, (CMTItem*)msg) != CMTSuccess) {
- goto loser;
- }
- certReqMsgs = SSM_ZNEW_ARRAY(CRMFCertReqMsg*, (request.numRequests+1));
- for (i=0; i<request.numRequests; i++) {
- rv = SSMControlConnection_GetResource(ctrl, (SSMResourceID)request.reqIDs[i],
- &res);
- if (rv != PR_SUCCESS) {
- goto loser;
- }
- if (!SSM_IsAKindOf(res, SSM_RESTYPE_CRMF_REQUEST)) {
- rv = PR_FAILURE;
- goto loser;
- }
- curReq = (SSMCRMFRequest*)res;
- certReqMsgs[i] = CRMF_CreateCertReqMsg();
- srv = CRMF_CertReqMsgSetCertRequest(certReqMsgs[i], curReq->m_CRMFRequest);
- if (srv != SECSuccess) {
- rv = PR_FAILURE;
- goto loser;
- }
- rv = SSMCRMFRequest_SetProofOfPossession(certReqMsgs[i], curReq);
- if (rv != PR_SUCCESS) {
- goto loser;
- }
-
- }
- /* Now we're ready to encode */
- messages.messages = certReqMsgs;
- encodedReq = SEC_ASN1EncodeItem(NULL, NULL, &messages,
- CRMFCertReqMessagesTemplate);
- if (encodedReq == NULL) {
- rv = PR_FAILURE;
- goto loser;
- }
- *destDER = BTOA_DataToAscii(encodedReq->data, encodedReq->len);
- *destLen = (*destDER == NULL) ? 0 : strlen(*destDER) + 1;
- SECITEM_FreeItem(encodedReq, PR_TRUE);
- rv = (*destDER == NULL) ? PR_FAILURE : PR_SUCCESS;
- loser:
- /* Do some massive memory clean-up in here. */
- if (certReqMsgs != NULL) {
- for (i=0; certReqMsgs[i] != NULL; i++){
- CRMF_DestroyCertReqMsg(certReqMsgs[i]);
- }
- PR_Free(certReqMsgs);
- }
- return rv;
- }
- void
- ssm_processcmmfresponse_thread(void *arg)
- {
- CMMFResponseArg *inArg = (CMMFResponseArg*)arg;
- SECItem *msg = inArg->msg;
- SSMControlConnection *connection = inArg->connection;
- SECStatus srv;
- SSMStatus rv;
- char *nickname=NULL;
- int numResponses, i;
- SECItem cmmfDer = {siBuffer, NULL, 0};
- PRArenaPool *ourPool = NULL;
- SECItem *derCerts = NULL;
- SSMPKCS12CreateArg p12Create;
- SSMResourceID p12RID;
- PRBool freeLocalNickname = PR_FALSE;
- SSMPKCS12Context *p12Cxt = NULL;
- CERTCertList *caPubs = NULL;
- CERTCertificate *currCert = NULL;
- CERTCertificate *dbCert = NULL;
- CMMFCertRepContent *certRepContent = NULL;
- CMMFCertResponse *currResponse = NULL;
- PK11SlotInfo *slot = NULL;
- CERTCertificate **certArr = NULL;
- CMMFPKIStatus reqStatus;
- PRBool certAlreadyExisted = PR_FALSE;
- CMMFCertResponseRequest request;
- if (CMT_DecodeMessage(CMMFCertResponseRequestTemplate, &request,
- (CMTItem*)msg) != CMTSuccess) {
- goto loser;
- }
- srv = ATOB_ConvertAsciiToItem(&cmmfDer, request.base64Der);
- if (srv != SECSuccess || cmmfDer.data == NULL) {
- goto loser;
- }
- certRepContent = CMMF_CreateCertRepContentFromDER(connection->m_certdb,
- (const char*)cmmfDer.data,
- cmmfDer.len);
- if (certRepContent == NULL) {
- /* This could be a key recovery response, but fail for now. */
- goto loser;
- }
- numResponses = CMMF_CertRepContentGetNumResponses(certRepContent);
- if (request.doBackup) {
- certArr = SSM_ZNEW_ARRAY(CERTCertificate*, numResponses);
- if (certArr == NULL) {
- /* Let's not do back up in this case. */
- request.doBackup = (CMBool) PR_FALSE;
- }
- }
- for (i=0; i<numResponses; i++) {
- currResponse = CMMF_CertRepContentGetResponseAtIndex(certRepContent, i);
- if (currResponse == NULL) {
- goto loser;
- }
- /* Need to make sure the ID corresponds to a request Cartman actually
- * made. Figure out how you're gonna do this.
- */
- reqStatus = CMMF_CertResponseGetPKIStatusInfoStatus(currResponse);
- if (!(reqStatus == cmmfGranted || reqStatus == cmmfGrantedWithMods)) {
- /* The CA didn't give us the cert as we requested. */
- goto loser;
- }
- currCert = CMMF_CertResponseGetCertificate(currResponse,
- connection->m_certdb);
- if (currCert == NULL) {
- goto loser;
- }
- if (!certificate_conflict(connection, &currCert->derCert,
- connection->m_certdb, !certAlreadyExisted)) {
- /* This certificate already exists in the permanent
- * database. Let's not add it and continue on
- * processing responses.
- */
- if (request.doBackup) {
- certArr[i] = currCert;
- } else {
- CERT_DestroyCertificate(currCert);
- }
- CMMF_DestroyCertResponse(currResponse);
- certAlreadyExisted = PR_TRUE;
- continue;
- }
-
- if (currCert->subjectList && currCert->subjectList->entry &&
- currCert->subjectList->entry->nickname) {
- nickname = currCert->subjectList->entry->nickname;
- } else if (request.nickname == NULL || request.nickname[0] == ' ') {
- nickname = default_nickname(currCert, connection);
- freeLocalNickname = PR_TRUE;
- } else {
- nickname = request.nickname;
- }
- slot = PK11_ImportCertForKey(currCert, nickname, connection);
- if (freeLocalNickname) {
- PR_Free(nickname);
- freeLocalNickname = PR_FALSE;
- }
- if (slot == NULL) {
- goto loser;
- }
- SSM_UseAsDefaultEmailIfNoneSet(connection, currCert, PR_TRUE);
- if (request.doBackup) {
- certArr[i] = currCert;
- } else {
- CERT_DestroyCertificate(currCert);
- }
- PK11_FreeSlot(slot);
- CMMF_DestroyCertResponse(currResponse);
- }
- caPubs = CMMF_CertRepContentGetCAPubs(certRepContent);
- if (caPubs != NULL) {
- CERTCertListNode *node;
- /* We got some CA certs to install in the database */
- ourPool = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
- if (ourPool == NULL) {
- goto loser;
- }
- derCerts = PORT_ArenaNewArray(ourPool, SECItem,
- SSM_CertListCount(caPubs));
- if (derCerts == NULL) {
- goto loser;
- }
- for (node = CERT_LIST_HEAD(caPubs), i=0;
- !CERT_LIST_END(node, caPubs);
- node = CERT_LIST_NEXT(node), i++) {
- srv = SECITEM_CopyItem(ourPool, &derCerts[i], &node->cert->derCert);
- if (srv != SECSuccess) {
- goto loser;
- }
- }
- srv = CERT_ImportCAChain(derCerts, SSM_CertListCount(caPubs),
- certUsageUserCertImport);
- if (srv != SECSuccess) {
- goto loser;
- }
- PORT_FreeArena(ourPool, PR_FALSE);
- }
- CMMF_DestroyCertRepContent(certRepContent);
- if (request.doBackup) {
- p12Create.isExportContext = PR_TRUE;
- rv = SSM_CreateResource(SSM_RESTYPE_PKCS12_CONTEXT,
- (void*)&p12Create,
- connection, &p12RID,
- (SSMResource**)(&p12Cxt));
- p12Cxt->arg = SSM_ZNEW(SSMPKCS12BackupThreadArg);
- if (p12Cxt->arg == NULL) {
- goto loser;
- }
- p12Cxt->arg->certs = certArr;
- p12Cxt->arg->numCerts = numResponses;
- p12Cxt->super.m_clientContext = request.clientContext;
- p12Cxt->m_thread = SSM_CreateThread(&p12Cxt->super,
- SSMPKCS12Context_BackupMultipleCertsThread);
-
- }
- PR_Free(request.base64Der);
- PR_Free(request.nickname);
- PR_FREEIF(msg->data);
- msg->data = NULL;
- msg->len = 0;
- msg->type = (SECItemType)(SSM_REPLY_OK_MESSAGE | SSM_CRMF_ACTION |
- SSM_PROCESS_CMMF_RESP);
- if (ssmcontrolconnection_send_message_to_client(connection, msg)
- != SSM_SUCCESS){
- goto loser;
- }
- SSM_FreeResource(&connection->super.super);
- SECITEM_FreeItem(msg, PR_TRUE);
- return;
- loser:
- if (connection != NULL) {
- SSM_FreeResource(&connection->super.super);
- }
- if (ourPool != NULL) {
- PORT_FreeArena(ourPool, PR_FALSE);
- }
- if (certRepContent != NULL) {
- CMMF_DestroyCertRepContent(certRepContent);
- }
- if (request.base64Der != NULL) {
- PR_Free(request.base64Der);
- }
- if (request.nickname != NULL) {
- PR_Free(request.nickname);
- }
- rv = ssmcontrolconnection_encode_err_reply(msg, SSM_FAILURE);
- PR_ASSERT(rv == SSM_SUCCESS);
- rv = ssmcontrolconnection_send_message_to_client(connection, msg);
- PR_ASSERT(rv == SSM_SUCCESS);
- }
- SSMStatus
- SSM_ProcessCMMFCertResponse(SECItem *msg, SSMControlConnection *connection)
- {
- CMMFResponseArg *arg=NULL;
- arg = SSM_NEW(CMMFResponseArg);
- if (arg == NULL) {
- goto loser;
- }
- arg->msg = SECITEM_DupItem(msg);
- arg->connection = connection;
- SSM_GetResourceReference(&connection->super.super);
- if (SSM_CreateAndRegisterThread(PR_USER_THREAD,
- ssm_processcmmfresponse_thread,
- (void *)arg, PR_PRIORITY_NORMAL,
- PR_LOCAL_THREAD,
- PR_UNJOINABLE_THREAD, 0) == NULL) {
- SSM_FreeResource(&connection->super.super);
- goto loser;
- }
- return SSM_ERR_DEFER_RESPONSE;
- loser:
- PR_FREEIF(arg);
- return SSM_FAILURE;
- }
- SECKEYPrivateKey*
- SSM_FindPrivKeyFromKeyID(SECItem *keyID, SECMODModule *currMod,
- SSMControlConnection *ctrl)
- {
- PK11SlotInfo *currSlot;
- SECKEYPrivateKey *privKey = NULL;
- int i;
- for (i=0; i<currMod->slotCount; i++) {
- currSlot = currMod->slots[i];
- privKey = PK11_FindKeyByKeyID(currSlot, keyID, (void*)ctrl);
- if (privKey != NULL) {
- break;
- }
- }
- return privKey;
- }
- SECKEYPrivateKey*
- SSM_FindPrivKeyFromPubValue(SECItem *publicValue, SECMODModuleList *modList,
- SSMControlConnection *ctrl)
- {
- SECItem *keyID = NULL;
- SECMODModuleList *currMod;
- SECKEYPrivateKey *privKey = NULL;
- keyID = PK11_MakeIDFromPubKey(publicValue);
- if (keyID == NULL) {
- return NULL;
- }
- /* Iterate through the slots looking for the slot where the private
- * key lives.
- */
- currMod = modList;
- while (currMod != NULL && currMod->module != NULL) {
- privKey = SSM_FindPrivKeyFromKeyID(keyID, currMod->module, ctrl);
- if (privKey != NULL) {
- break;
- }
- currMod = currMod->next;
- }
- SECITEM_FreeItem(keyID, PR_TRUE);
- return privKey;
- }
- SSMStatus
- SSM_InitCRMFASN1Arg(CRMFASN1Arg *arg)
- {
- arg->buffer.data = SSM_NEW_ARRAY(unsigned char, DEFAULT_ASN1_CHUNK_SIZE);
- if (arg->buffer.data == NULL) {
- return PR_FAILURE;
- }
- arg->buffer.len = 0;
- arg->allocatedLen = DEFAULT_ASN1_CHUNK_SIZE;
- return PR_FAILURE;
- }
- void
- SSM_GenericASN1Callback(void *arg, const char *buf, unsigned long len)
- {
- CRMFASN1Arg *encoderArg = (CRMFASN1Arg*)arg;
- unsigned char *cursor;
-
- if ((encoderArg->buffer.len + len) > encoderArg->allocatedLen) {
- int newSize = encoderArg->buffer.len + DEFAULT_ASN1_CHUNK_SIZE;
- void *dummy = PR_Realloc(encoderArg->buffer.data, newSize);
- if (dummy == NULL) {
- PR_ASSERT(0);
- return;
- }
- encoderArg->buffer.data = (unsigned char *) dummy;
- encoderArg->allocatedLen = newSize;
- }
- cursor = &(encoderArg->buffer.data[encoderArg->buffer.len]);
- memcpy(cursor, buf, len);
- encoderArg->buffer.len += len;
- }
- SSMStatus
- SSM_RespondToPOPChallenge(SECItem *msg,
- SSMControlConnection *ctrl,
- char **challengeResponse,
- PRUint32 *responseLen)
- {
- SSMStatus rv;
- SECStatus srv;
- SECItem challengeDER = {siBuffer, NULL, 0}, *publicValue=NULL;
- int i, numChallenges;
- long *decryptedChallenges=NULL;
- CMMFPOPODecKeyChallContent *challContent = NULL;
- SECMODModuleList *modList = NULL;
- SECKEYPrivateKey *privKey = NULL;
- CRMFASN1Arg asn1Arg = {{(SECItemType) 0, NULL, 0}, 0};
- SingleStringMessage request;
- if (CMT_DecodeMessage(SingleStringMessageTemplate, &request, (CMTItem*)msg) != CMTSuccess) {
- goto loser;
- }
- srv = ATOB_ConvertAsciiToItem(&challengeDER, request.string);
- if (srv != SECSuccess) {
- goto loser;
- }
- challContent = CMMF_CreatePOPODecKeyChallContentFromDER((char *) challengeDER.data,
- (unsigned int) challengeDER.len);
- if (challContent == NULL) {
- goto loser;
- }
- numChallenges = CMMF_POPODecKeyChallContentGetNumChallenges(challContent);
- if (numChallenges <= 0) {
- /* There weren't any challenges in the challenge string. */
- goto loser;
- }
- modList = SECMOD_GetDefaultModuleList();
- if (modList == NULL) {
- goto loser;
- }
- decryptedChallenges = SSM_ZNEW_ARRAY(long, (numChallenges+1));
- if (decryptedChallenges == NULL) {
- goto loser;
- }
- for (i=0; i<numChallenges; i++) {
- publicValue =
- CMMF_POPODecKeyChallContentGetPublicValue(challContent, i);
- if (publicValue == NULL) {
- goto loser;
- }
- privKey = SSM_FindPrivKeyFromPubValue(publicValue, modList, ctrl);
- if (privKey == NULL) {
- goto loser;
- }
- SECITEM_FreeItem(publicValue, PR_TRUE);
- publicValue = NULL;
- srv = CMMF_POPODecKeyChallContDecryptChallenge(challContent, i,
- privKey);
- if (srv != SECSuccess) {
- goto loser;
- }
- srv = CMMF_POPODecKeyChallContentGetRandomNumber(challContent, i,
- &decryptedChallenges[i]);
- if (srv != SECSuccess) {
- goto loser;
- }
- }
- modList = NULL;
- CMMF_DestroyPOPODecKeyChallContent(challContent);
- challContent = NULL;
- rv = SSM_InitCRMFASN1Arg(&asn1Arg);
- srv = CMMF_EncodePOPODecKeyRespContent(decryptedChallenges, numChallenges,
- SSM_GenericASN1Callback, &asn1Arg);
- if (srv != SECSuccess) {
- goto loser;
- }
- *challengeResponse = BTOA_DataToAscii(asn1Arg.buffer.data,
- asn1Arg.buffer.len);
- PR_Free(asn1Arg.buffer.data);
- *responseLen = (*challengeResponse == NULL) ? 0 :
- strlen(*challengeResponse)+1;
- PR_Free(decryptedChallenges);
- PR_Free(request.string);
- return PR_SUCCESS;
- loser:
- if (asn1Arg.buffer.data != NULL) {
- PR_Free(asn1Arg.buffer.data);
- }
- if (decryptedChallenges != NULL) {
- PR_Free(decryptedChallenges);
- }
- if (request.string != NULL) {
- PR_Free(request.string);
- }
- if (challContent != NULL) {
- CMMF_DestroyPOPODecKeyChallContent(challContent);
- }
- if (publicValue != NULL) {
- SECITEM_FreeItem(publicValue, PR_TRUE);
- }
- if (modList != NULL) {
- SECMOD_DestroyModuleList(modList);
- }
- return PR_FAILURE;
- }
- void SSM_CRMFEncodeThread(void *arg)
- {
- SSMCRMFThreadArg *encArg = (SSMCRMFThreadArg*)arg;
- SSMControlConnection *ctrl = encArg->ctrl;
- SECItem *msg = encArg->msg;
- char *encodedReq = NULL;
- PRUint32 derLen;
- SingleItemMessage reply;
- SSMStatus rv;
- SSM_RegisterThread("CRMF Encode", NULL);
- SSM_DEBUG("Encoding CRMF request(s)n");
- rv = SSM_EncodeCRMFRequests(ctrl, msg, &encodedReq, &derLen);
- if (rv != PR_SUCCESS) {
- goto loser;
- }
- msg->data = NULL;
- msg->len = 0;
- msg->type = (SECItemType) (SSM_REPLY_OK_MESSAGE |
- SSM_CRMF_ACTION |
- SSM_DER_ENCODE_REQ);
- reply.item.len = derLen;
- reply.item.data = (unsigned char *) encodedReq;
- if (CMT_EncodeMessage(SingleItemMessageTemplate,
- (CMTItem*)msg, &reply) != CMTSuccess) {
- goto loser;
- }
- SSM_DEBUG("Created the following request: n");
- SSM_DEBUG("n%sn",encodedReq);
- PR_Free(encodedReq);
- SSM_DEBUG("queueing reply: type %lx, len %ld.n", msg->type, msg->len);
- SSM_SendQMessage(ctrl->m_controlOutQ,
- SSM_PRIORITY_NORMAL,
- msg->type, msg->len,
- (char *)msg->data, PR_TRUE);
- goto done;
- loser:
- {
- SingleNumMessage reply;
- msg->type = (SECItemType) SSM_REPLY_ERR_MESSAGE;
- reply.value = rv;
- CMT_EncodeMessage(SingleNumMessageTemplate, (CMTItem*)msg, &reply);
- }
- SSM_DEBUG("queueing reply: type %lx, len %ld.n", msg->type, msg->len);
- SSM_SendQMessage(ctrl->m_controlOutQ,
- SSM_PRIORITY_NORMAL,
- msg->type, msg->len,
- (char *)msg->data, PR_TRUE);
- done:
- SSM_FreeResource(&ctrl->super.super);
- SECITEM_FreeItem(msg, PR_TRUE);
- PR_Free(arg);
- }