security/nss/lib/crmf/crmfcont.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C; tab-width: 8 -*-*/
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "crmf.h"
     7 #include "crmfi.h"
     8 #include "pk11func.h"
     9 #include "keyhi.h"
    10 #include "secoid.h"
    12 static SECStatus
    13 crmf_modify_control_array (CRMFCertRequest *inCertReq, int count)
    14 {
    15     if (count > 0) {
    16         void *dummy = PORT_Realloc(inCertReq->controls, 
    17 				   sizeof(CRMFControl*)*(count+2));
    18 	if (dummy == NULL) {
    19 	    return SECFailure;
    20 	}
    21 	inCertReq->controls = dummy;
    22     } else {
    23         inCertReq->controls = PORT_ZNewArray(CRMFControl*, 2);
    24     }
    25     return (inCertReq->controls == NULL) ? SECFailure : SECSuccess ;
    26 }
    28 static SECStatus
    29 crmf_add_new_control(CRMFCertRequest *inCertReq,SECOidTag inTag,
    30 		     CRMFControl **destControl)
    31 {
    32     SECOidData  *oidData;
    33     SECStatus    rv;
    34     PLArenaPool *poolp;
    35     int          numControls = 0;
    36     CRMFControl *newControl;
    37     CRMFControl **controls;
    38     void        *mark;
    40     poolp = inCertReq->poolp;
    41     if (poolp == NULL) {
    42         return SECFailure;
    43     }
    44     mark = PORT_ArenaMark(poolp);
    45     if (inCertReq->controls != NULL) {
    46         while (inCertReq->controls[numControls] != NULL)
    47 	    numControls++;
    48     }
    49     rv = crmf_modify_control_array(inCertReq, numControls);
    50     if (rv != SECSuccess) {
    51         goto loser;
    52     }
    53     controls = inCertReq->controls;
    54     oidData = SECOID_FindOIDByTag(inTag);
    55     newControl = *destControl = PORT_ArenaZNew(poolp,CRMFControl);
    56     if (newControl == NULL) {
    57         goto loser;
    58     }
    59     rv = SECITEM_CopyItem(poolp, &newControl->derTag, &oidData->oid);
    60     if (rv != SECSuccess) {
    61         goto loser;
    62     }
    63     newControl->tag = inTag;
    64     controls[numControls] = newControl;
    65     controls[numControls+1] = NULL;
    66     PORT_ArenaUnmark(poolp, mark);
    67     return SECSuccess;
    69  loser:
    70     PORT_ArenaRelease(poolp, mark);
    71     *destControl = NULL;
    72     return SECFailure;
    74 }
    76 static SECStatus
    77 crmf_add_secitem_control(CRMFCertRequest *inCertReq, SECItem *value,
    78 			 SECOidTag inTag)
    79 {
    80     SECStatus    rv;
    81     CRMFControl *newControl;
    82     void        *mark;
    84     rv = crmf_add_new_control(inCertReq, inTag, &newControl);
    85     if (rv != SECSuccess) {
    86         return rv;
    87     }
    88     mark = PORT_ArenaMark(inCertReq->poolp);
    89     rv = SECITEM_CopyItem(inCertReq->poolp, &newControl->derValue, value);
    90     if (rv != SECSuccess) {
    91         PORT_ArenaRelease(inCertReq->poolp, mark);
    92 	return rv;
    93     }
    94     PORT_ArenaUnmark(inCertReq->poolp, mark);
    95     return SECSuccess;
    96 }
    98 SECStatus
    99 CRMF_CertRequestSetRegTokenControl(CRMFCertRequest *inCertReq, SECItem *value)
   100 {
   101     return crmf_add_secitem_control(inCertReq, value, 
   102 				    SEC_OID_PKIX_REGCTRL_REGTOKEN);
   103 }
   105 SECStatus
   106 CRMF_CertRequestSetAuthenticatorControl (CRMFCertRequest *inCertReq, 
   107 					 SECItem         *value)
   108 {
   109     return crmf_add_secitem_control(inCertReq, value, 
   110 				    SEC_OID_PKIX_REGCTRL_AUTHENTICATOR);
   111 }
   113 SECStatus
   114 crmf_destroy_encrypted_value(CRMFEncryptedValue *inEncrValue, PRBool freeit)
   115 {
   116     if (inEncrValue != NULL) {
   117         if (inEncrValue->intendedAlg) {
   118 	    SECOID_DestroyAlgorithmID(inEncrValue->intendedAlg, PR_TRUE);
   119 	    inEncrValue->intendedAlg = NULL;
   120 	}
   121 	if (inEncrValue->symmAlg) {
   122 	    SECOID_DestroyAlgorithmID(inEncrValue->symmAlg, PR_TRUE);
   123 	    inEncrValue->symmAlg = NULL;
   124 	}
   125         if (inEncrValue->encSymmKey.data) {
   126 	    PORT_Free(inEncrValue->encSymmKey.data);
   127 	    inEncrValue->encSymmKey.data = NULL;
   128 	}
   129 	if (inEncrValue->keyAlg) {
   130 	    SECOID_DestroyAlgorithmID(inEncrValue->keyAlg, PR_TRUE);
   131 	    inEncrValue->keyAlg = NULL;
   132 	}
   133 	if (inEncrValue->valueHint.data) {
   134 	    PORT_Free(inEncrValue->valueHint.data);
   135 	    inEncrValue->valueHint.data = NULL;
   136 	}
   137         if (inEncrValue->encValue.data) {
   138 	    PORT_Free(inEncrValue->encValue.data);
   139 	    inEncrValue->encValue.data = NULL;
   140 	}
   141 	if (freeit) {
   142 	    PORT_Free(inEncrValue);
   143 	}
   144     }
   145     return SECSuccess;
   146 }
   148 SECStatus
   149 CRMF_DestroyEncryptedValue(CRMFEncryptedValue *inEncrValue)
   150 {
   151     return crmf_destroy_encrypted_value(inEncrValue, PR_TRUE);
   152 }
   154 SECStatus
   155 crmf_copy_encryptedvalue_secalg(PLArenaPool     *poolp,
   156 				SECAlgorithmID  *srcAlgId,
   157 				SECAlgorithmID **destAlgId)
   158 {
   159     SECAlgorithmID *newAlgId;
   160     SECStatus rv;
   162     newAlgId = (poolp != NULL) ? PORT_ArenaZNew(poolp, SECAlgorithmID) :
   163                                  PORT_ZNew(SECAlgorithmID);
   164     if (newAlgId == NULL) {
   165         return SECFailure;
   166     }
   168     rv = SECOID_CopyAlgorithmID(poolp, newAlgId, srcAlgId);
   169     if (rv != SECSuccess) {
   170         if (!poolp) {
   171             SECOID_DestroyAlgorithmID(newAlgId, PR_TRUE);
   172         }
   173         return rv;
   174     }
   175     *destAlgId = newAlgId;
   177     return rv;
   178 }
   180 SECStatus
   181 crmf_copy_encryptedvalue(PLArenaPool        *poolp,
   182 			 CRMFEncryptedValue *srcValue,
   183 			 CRMFEncryptedValue *destValue)
   184 {
   185     SECStatus           rv;
   187     if (srcValue->intendedAlg != NULL) {
   188         rv = crmf_copy_encryptedvalue_secalg(poolp,
   189 					     srcValue->intendedAlg,
   190 					     &destValue->intendedAlg);
   191 	if (rv != SECSuccess) {
   192 	    goto loser;
   193 	}
   194     }
   195     if (srcValue->symmAlg != NULL) {
   196         rv = crmf_copy_encryptedvalue_secalg(poolp, 
   197 					     srcValue->symmAlg,
   198 					     &destValue->symmAlg);
   199 	if (rv != SECSuccess) {
   200 	    goto loser;
   201 	}
   202     }
   203     if (srcValue->encSymmKey.data != NULL) {
   204         rv = crmf_make_bitstring_copy(poolp, 
   205 				      &destValue->encSymmKey,
   206 				      &srcValue->encSymmKey);
   207 	if (rv != SECSuccess) {
   208 	    goto loser;
   209 	}
   210     }
   211     if (srcValue->keyAlg != NULL) {
   212         rv = crmf_copy_encryptedvalue_secalg(poolp,
   213 					     srcValue->keyAlg,
   214 					     &destValue->keyAlg);
   215 	if (rv != SECSuccess) {
   216 	    goto loser;
   217 	}
   218     }
   219     if (srcValue->valueHint.data != NULL) {
   220         rv = SECITEM_CopyItem(poolp, 
   221 			      &destValue->valueHint,
   222 			      &srcValue->valueHint);
   223 	if (rv != SECSuccess) {
   224 	    goto loser;
   225 	}
   226     }
   227     if (srcValue->encValue.data != NULL) {
   228         rv = crmf_make_bitstring_copy(poolp,
   229 				      &destValue->encValue,
   230 				      &srcValue->encValue);
   231 	if (rv != SECSuccess) {
   232 	    goto loser;
   233 	}
   234     }
   235     return SECSuccess;
   236  loser:
   237     if (poolp == NULL && destValue != NULL) {
   238         crmf_destroy_encrypted_value(destValue, PR_FALSE);
   239     }
   240     return SECFailure;
   241 }
   243 SECStatus 
   244 crmf_copy_encryptedkey(PLArenaPool       *poolp,
   245 		       CRMFEncryptedKey  *srcEncrKey,
   246 		       CRMFEncryptedKey  *destEncrKey)
   247 {
   248     SECStatus          rv;
   249     void              *mark = NULL;
   251     if (poolp != NULL) {
   252         mark = PORT_ArenaMark(poolp);
   253     }
   255     switch (srcEncrKey->encKeyChoice) {
   256     case crmfEncryptedValueChoice:
   257         rv = crmf_copy_encryptedvalue(poolp, 
   258 				      &srcEncrKey->value.encryptedValue,
   259 				      &destEncrKey->value.encryptedValue);
   260 	break;
   261     case crmfEnvelopedDataChoice:
   262         destEncrKey->value.envelopedData = 
   263 	    SEC_PKCS7CopyContentInfo(srcEncrKey->value.envelopedData);
   264         rv = (destEncrKey->value.envelopedData != NULL) ? SECSuccess:
   265 	                                                  SECFailure;
   266         break;
   267     default:
   268         rv = SECFailure;
   269     }
   270     if (rv != SECSuccess) {
   271         goto loser;
   272     }
   273     destEncrKey->encKeyChoice = srcEncrKey->encKeyChoice;
   274     if (mark) {
   275     	PORT_ArenaUnmark(poolp, mark);
   276     }
   277     return SECSuccess;
   279  loser:
   280     if (mark) {
   281         PORT_ArenaRelease(poolp, mark);
   282     }
   283     return SECFailure;
   284 }
   286 static CRMFPKIArchiveOptions*
   287 crmf_create_encr_pivkey_option(CRMFEncryptedKey *inEncryptedKey)
   288 {
   289     CRMFPKIArchiveOptions *newArchOpt;
   290     SECStatus              rv;
   292     newArchOpt = PORT_ZNew(CRMFPKIArchiveOptions);
   293     if (newArchOpt == NULL) {
   294         goto loser;
   295     }
   297     rv = crmf_copy_encryptedkey(NULL, inEncryptedKey,
   298 				&newArchOpt->option.encryptedKey);
   300     if (rv != SECSuccess) {
   301       goto loser;
   302     }
   303     newArchOpt->archOption = crmfEncryptedPrivateKey;
   304     return newArchOpt;
   305  loser:
   306     if (newArchOpt != NULL) {
   307         CRMF_DestroyPKIArchiveOptions(newArchOpt);
   308     }
   309     return NULL;
   310 }
   312 static CRMFPKIArchiveOptions*
   313 crmf_create_keygen_param_option(SECItem *inKeyGenParams)
   314 {
   315     CRMFPKIArchiveOptions *newArchOptions;
   316     SECStatus              rv;
   318     newArchOptions = PORT_ZNew(CRMFPKIArchiveOptions);
   319     if (newArchOptions == NULL) {
   320         goto loser;
   321     }
   322     newArchOptions->archOption = crmfKeyGenParameters;
   323     rv = SECITEM_CopyItem(NULL, &newArchOptions->option.keyGenParameters,
   324 			  inKeyGenParams);
   325     if (rv != SECSuccess) {
   326         goto loser;
   327     }
   328     return newArchOptions;
   329  loser:
   330     if (newArchOptions != NULL) {
   331         CRMF_DestroyPKIArchiveOptions(newArchOptions);
   332     }
   333     return NULL;
   334 }
   336 static CRMFPKIArchiveOptions*
   337 crmf_create_arch_rem_gen_privkey(PRBool archiveRemGenPrivKey)
   338 {
   339     unsigned char          value;
   340     SECItem               *dummy;
   341     CRMFPKIArchiveOptions *newArchOptions;
   343     value = (archiveRemGenPrivKey) ? hexTrue : hexFalse;
   344     newArchOptions = PORT_ZNew(CRMFPKIArchiveOptions);
   345     if (newArchOptions == NULL) {
   346         goto loser;
   347     }
   348     dummy = SEC_ASN1EncodeItem(NULL, 
   349 			       &newArchOptions->option.archiveRemGenPrivKey,
   350 			       &value, SEC_ASN1_GET(SEC_BooleanTemplate));
   351     PORT_Assert (dummy == &newArchOptions->option.archiveRemGenPrivKey);
   352     if (dummy != &newArchOptions->option.archiveRemGenPrivKey) {
   353         SECITEM_FreeItem (dummy, PR_TRUE);
   354 	goto loser;
   355     }
   356     newArchOptions->archOption = crmfArchiveRemGenPrivKey;
   357     return newArchOptions;
   358  loser:
   359     if (newArchOptions != NULL) {
   360         CRMF_DestroyPKIArchiveOptions(newArchOptions);
   361     }
   362     return NULL;
   363 }
   365 CRMFPKIArchiveOptions*
   366 CRMF_CreatePKIArchiveOptions(CRMFPKIArchiveOptionsType inType, void *data)
   367 {
   368     CRMFPKIArchiveOptions* retOptions;
   370     PORT_Assert(data != NULL);
   371     if (data == NULL) {
   372         return NULL;
   373     }
   374     switch(inType) {
   375     case crmfEncryptedPrivateKey:
   376         retOptions = crmf_create_encr_pivkey_option((CRMFEncryptedKey*)data);
   377 	break;
   378     case crmfKeyGenParameters:
   379         retOptions = crmf_create_keygen_param_option((SECItem*)data);
   380 	break;
   381     case crmfArchiveRemGenPrivKey:
   382         retOptions = crmf_create_arch_rem_gen_privkey(*(PRBool*)data);
   383 	break;
   384     default:
   385         retOptions = NULL;
   386     }
   387     return retOptions;
   388 }
   390 static SECStatus
   391 crmf_destroy_encrypted_key(CRMFEncryptedKey *inEncrKey, PRBool freeit)
   392 { 
   393     PORT_Assert(inEncrKey != NULL);
   394     if (inEncrKey != NULL) {
   395         switch (inEncrKey->encKeyChoice){
   396 	case crmfEncryptedValueChoice:
   397             crmf_destroy_encrypted_value(&inEncrKey->value.encryptedValue, 
   398 					 PR_FALSE);
   399 	    break;
   400 	case crmfEnvelopedDataChoice:
   401 	    SEC_PKCS7DestroyContentInfo(inEncrKey->value.envelopedData);
   402             break;
   403         default:
   404             break;
   405         }
   406         if (freeit) {
   407             PORT_Free(inEncrKey);
   408         }
   409     }
   410     return SECSuccess;
   411 }
   413 SECStatus 
   414 crmf_destroy_pkiarchiveoptions(CRMFPKIArchiveOptions *inArchOptions, 
   415 			       PRBool                 freeit)
   416 {
   417     PORT_Assert(inArchOptions != NULL);
   418     if (inArchOptions != NULL) {
   419         switch (inArchOptions->archOption) {
   420 	case crmfEncryptedPrivateKey:
   421 	    crmf_destroy_encrypted_key(&inArchOptions->option.encryptedKey,
   422 				       PR_FALSE);
   423 	    break;
   424 	case crmfKeyGenParameters:
   425 	case crmfArchiveRemGenPrivKey:
   426 	    /* This is a union, so having a pointer to one is like
   427 	     * having a pointer to both.  
   428 	     */
   429 	    SECITEM_FreeItem(&inArchOptions->option.keyGenParameters, 
   430 			     PR_FALSE);
   431 	    break;
   432         case crmfNoArchiveOptions:
   433             break;
   434 	}
   435 	if (freeit) {
   436 	    PORT_Free(inArchOptions);
   437 	}
   438     }
   439     return SECSuccess;
   440 }
   442 SECStatus
   443 CRMF_DestroyPKIArchiveOptions(CRMFPKIArchiveOptions *inArchOptions) 
   444 {
   445     return crmf_destroy_pkiarchiveoptions(inArchOptions, PR_TRUE);
   446 }
   448 static CK_MECHANISM_TYPE
   449 crmf_get_non_pad_mechanism(CK_MECHANISM_TYPE type)
   450 {
   451     switch (type) {
   452     case CKM_DES3_CBC_PAD:
   453         return CKM_DES3_CBC;
   454     case CKM_CAST5_CBC_PAD:
   455         return CKM_CAST5_CBC;
   456     case CKM_DES_CBC_PAD:
   457         return CKM_DES_CBC;
   458     case CKM_IDEA_CBC_PAD:
   459         return CKM_IDEA_CBC;
   460     case CKM_CAST3_CBC_PAD:
   461         return CKM_CAST3_CBC;
   462     case CKM_CAST_CBC_PAD:
   463         return CKM_CAST_CBC;
   464     case CKM_RC5_CBC_PAD:
   465         return CKM_RC5_CBC;
   466     case CKM_RC2_CBC_PAD:
   467         return CKM_RC2_CBC;
   468     case CKM_CDMF_CBC_PAD:
   469         return CKM_CDMF_CBC;
   470     }
   471     return type;
   472 }
   474 static CK_MECHANISM_TYPE
   475 crmf_get_pad_mech_from_tag(SECOidTag oidTag)
   476 {
   477     CK_MECHANISM_TYPE  mechType;
   478     SECOidData        *oidData;
   480     oidData = SECOID_FindOIDByTag(oidTag);
   481     mechType = (CK_MECHANISM_TYPE)oidData->mechanism;
   482     return PK11_GetPadMechanism(mechType);
   483 }
   485 static CK_MECHANISM_TYPE
   486 crmf_get_best_privkey_wrap_mechanism(PK11SlotInfo *slot) 
   487 {
   488     CK_MECHANISM_TYPE privKeyPadMechs[] = { CKM_DES3_CBC_PAD,
   489 					    CKM_CAST5_CBC_PAD,
   490 					    CKM_DES_CBC_PAD,
   491 					    CKM_IDEA_CBC_PAD,
   492 					    CKM_CAST3_CBC_PAD,
   493 					    CKM_CAST_CBC_PAD,
   494 					    CKM_RC5_CBC_PAD,
   495 					    CKM_RC2_CBC_PAD,
   496 					    CKM_CDMF_CBC_PAD };
   497     int mechCount = sizeof(privKeyPadMechs)/sizeof(privKeyPadMechs[0]);
   498     int i;
   500     for (i=0; i < mechCount; i++) {
   501         if (PK11_DoesMechanism(slot, privKeyPadMechs[i])) {
   502 	    return privKeyPadMechs[i];
   503 	}
   504     }
   505     return CKM_INVALID_MECHANISM;
   506 }
   508 CK_MECHANISM_TYPE
   509 CRMF_GetBestWrapPadMechanism(PK11SlotInfo *slot)
   510 {
   511     return crmf_get_best_privkey_wrap_mechanism(slot);
   512 }
   514 static SECItem*
   515 crmf_get_iv(CK_MECHANISM_TYPE mechType)
   516 {
   517     int        iv_size = PK11_GetIVLength(mechType);
   518     SECItem   *iv;
   519     SECStatus  rv; 
   521     iv = PORT_ZNew(SECItem);
   522     if (iv == NULL) {
   523         return NULL;
   524     }
   525     if (iv_size == 0) {
   526         iv->data = NULL;
   527 	iv->len  = 0;
   528 	return iv;
   529     }
   530     iv->data = PORT_NewArray(unsigned char, iv_size);
   531     if (iv->data == NULL) {
   532         iv->len = 0;
   533 	return iv;
   534     }
   535     iv->len = iv_size;
   536     rv = PK11_GenerateRandom(iv->data, iv->len);
   537     if (rv != SECSuccess) {
   538         PORT_Free(iv->data);
   539 	iv->data = NULL;
   540 	iv->len  = 0;
   541     }
   542     return iv;
   543 }
   545 SECItem*
   546 CRMF_GetIVFromMechanism(CK_MECHANISM_TYPE mechType)
   547 {
   548     return crmf_get_iv(mechType);
   549 }
   551 CK_MECHANISM_TYPE
   552 crmf_get_mechanism_from_public_key(SECKEYPublicKey *inPubKey)
   553 {
   554     CERTSubjectPublicKeyInfo *spki = NULL;
   555     SECOidTag                 tag;
   558     spki = SECKEY_CreateSubjectPublicKeyInfo(inPubKey);
   559     if (spki == NULL) {
   560         return CKM_INVALID_MECHANISM;
   561     }
   562     tag = SECOID_FindOIDTag(&spki->algorithm.algorithm);
   563     SECKEY_DestroySubjectPublicKeyInfo(spki);
   564     spki = NULL;
   565     return PK11_AlgtagToMechanism(tag);
   566 }
   568 SECItem*
   569 crmf_get_public_value(SECKEYPublicKey *pubKey, SECItem *dest)
   570 {
   571     SECItem *src;
   573     switch(pubKey->keyType) {
   574     case dsaKey:
   575 	src =  &pubKey->u.dsa.publicValue;
   576 	break;
   577     case rsaKey:
   578 	src =  &pubKey->u.rsa.modulus;
   579 	break;
   580     case dhKey:
   581 	src =  &pubKey->u.dh.publicValue;
   582 	break;
   583     default:
   584 	src = NULL;
   585 	break;
   586     }
   587     if (!src) {
   588 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
   589 	return NULL;
   590     }
   592     if (dest != NULL) {
   593 	SECStatus rv = SECITEM_CopyItem(NULL, dest, src);
   594 	if (rv != SECSuccess) {
   595 	    dest = NULL;
   596 	}
   597     } else {
   598         dest = SECITEM_ArenaDupItem(NULL, src);
   599     }
   600     return dest;
   601 }
   603 static SECItem*
   604 crmf_decode_params(SECItem *inParams)
   605 {
   606     SECItem     *params;
   607     SECStatus    rv      = SECFailure;
   608     PLArenaPool *poolp;
   610     poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
   611     if (poolp == NULL) {
   612         return NULL;
   613     }
   615     params = PORT_ArenaZNew(poolp, SECItem);
   616     if (params) {
   617 	rv = SEC_ASN1DecodeItem(poolp, params, 
   618 				SEC_ASN1_GET(SEC_OctetStringTemplate),
   619 				inParams);
   620     }
   621     params = (rv == SECSuccess) ? SECITEM_ArenaDupItem(NULL, params) : NULL;
   622     PORT_FreeArena(poolp, PR_FALSE);
   623     return params;
   624 }
   626 static int
   627 crmf_get_key_size_from_mech(CK_MECHANISM_TYPE mechType)
   628 {
   629     CK_MECHANISM_TYPE keyGen = PK11_GetKeyGen(mechType);
   631     switch (keyGen) {
   632     case CKM_CDMF_KEY_GEN:
   633     case CKM_DES_KEY_GEN:
   634         return 8;
   635     case CKM_DES2_KEY_GEN:
   636 	return 16;
   637     case CKM_DES3_KEY_GEN:
   638 	return 24;
   639     }
   640     return 0;
   641 }
   643 SECStatus
   644 crmf_encrypted_value_unwrap_priv_key(PLArenaPool        *poolp,
   645 				     CRMFEncryptedValue *encValue,
   646 				     SECKEYPrivateKey   *privKey,
   647 				     SECKEYPublicKey    *newPubKey,
   648 				     SECItem            *nickname,
   649 				     PK11SlotInfo       *slot,
   650 				     unsigned char       keyUsage,
   651 				     SECKEYPrivateKey  **unWrappedKey,
   652 				     void               *wincx)
   653 {
   654     PK11SymKey        *wrappingKey = NULL;
   655     CK_MECHANISM_TYPE  wrapMechType;
   656     SECOidTag          oidTag;
   657     SECItem           *params = NULL, *publicValue = NULL;
   658     int                keySize, origLen;
   659     CK_KEY_TYPE        keyType;
   660     CK_ATTRIBUTE_TYPE *usage = NULL;
   661     CK_ATTRIBUTE_TYPE rsaUsage[] = {
   662       CKA_UNWRAP, CKA_DECRYPT, CKA_SIGN, CKA_SIGN_RECOVER };
   663     CK_ATTRIBUTE_TYPE dsaUsage[] = { CKA_SIGN };
   664     CK_ATTRIBUTE_TYPE dhUsage[] = { CKA_DERIVE };
   665     int usageCount = 0;
   667     oidTag = SECOID_GetAlgorithmTag(encValue->symmAlg);
   668     wrapMechType = crmf_get_pad_mech_from_tag(oidTag);
   669     keySize = crmf_get_key_size_from_mech(wrapMechType);
   670     wrappingKey = PK11_PubUnwrapSymKey(privKey, &encValue->encSymmKey, 
   671 				       wrapMechType, CKA_UNWRAP, keySize);
   672     if (wrappingKey == NULL) {
   673         goto loser;
   674     }/* Make the length a byte length instead of bit length*/
   675     params = (encValue->symmAlg != NULL) ? 
   676               crmf_decode_params(&encValue->symmAlg->parameters) : NULL;
   677     origLen = encValue->encValue.len;
   678     encValue->encValue.len = CRMF_BITS_TO_BYTES(origLen);
   679     publicValue = crmf_get_public_value(newPubKey, NULL);
   680     switch(newPubKey->keyType) {
   681     default:
   682     case rsaKey:
   683         keyType = CKK_RSA;
   684         switch  (keyUsage & (KU_KEY_ENCIPHERMENT|KU_DIGITAL_SIGNATURE)) {
   685         case KU_KEY_ENCIPHERMENT:
   686             usage = rsaUsage;
   687             usageCount = 2;
   688             break;
   689         case KU_DIGITAL_SIGNATURE:
   690             usage = &rsaUsage[2];
   691             usageCount = 2;
   692             break;
   693         case KU_KEY_ENCIPHERMENT|KU_DIGITAL_SIGNATURE:
   694         case 0: /* default to everything */
   695             usage = rsaUsage;
   696             usageCount = 4;
   697             break;
   698         }
   699 	break;
   700     case dhKey:
   701         keyType = CKK_DH;
   702         usage = dhUsage;
   703         usageCount = sizeof(dhUsage)/sizeof(dhUsage[0]);
   704         break;
   705     case dsaKey:
   706         keyType = CKK_DSA;
   707         usage = dsaUsage;
   708         usageCount = sizeof(dsaUsage)/sizeof(dsaUsage[0]);
   709         break;
   710     }
   711     PORT_Assert(usage != NULL);
   712     PORT_Assert(usageCount != 0);
   713     *unWrappedKey = PK11_UnwrapPrivKey(slot, wrappingKey, wrapMechType, params,
   714 				       &encValue->encValue, nickname,
   715 				       publicValue, PR_TRUE,PR_TRUE, 
   716 				       keyType, usage, usageCount, wincx);
   717     encValue->encValue.len = origLen;
   718     if (*unWrappedKey == NULL) {
   719         goto loser;
   720     }
   721     SECITEM_FreeItem (publicValue, PR_TRUE);
   722     if (params!= NULL) {
   723         SECITEM_FreeItem(params, PR_TRUE);
   724     } 
   725     PK11_FreeSymKey(wrappingKey);
   726     return SECSuccess;
   727  loser:
   728     *unWrappedKey = NULL;
   729     return SECFailure;
   730 }
   732 CRMFEncryptedValue *
   733 crmf_create_encrypted_value_wrapped_privkey(SECKEYPrivateKey   *inPrivKey,
   734 					    SECKEYPublicKey    *inCAKey,
   735 					    CRMFEncryptedValue *destValue)
   736 {
   737     SECItem                   wrappedPrivKey, wrappedSymKey;
   738     SECItem                   encodedParam, *dummy;
   739     SECStatus                 rv;
   740     CK_MECHANISM_TYPE         pubMechType, symKeyType;
   741     unsigned char            *wrappedSymKeyBits;
   742     unsigned char            *wrappedPrivKeyBits;
   743     SECItem                  *iv = NULL;
   744     SECOidTag                 tag;
   745     PK11SymKey               *symKey;
   746     PK11SlotInfo             *slot;
   747     SECAlgorithmID           *symmAlg;
   748     CRMFEncryptedValue       *myEncrValue = NULL;
   750     encodedParam.data = NULL;
   751     wrappedSymKeyBits  = PORT_NewArray(unsigned char, MAX_WRAPPED_KEY_LEN);
   752     wrappedPrivKeyBits = PORT_NewArray(unsigned char, MAX_WRAPPED_KEY_LEN);
   753     if (wrappedSymKeyBits == NULL || wrappedPrivKeyBits == NULL) {
   754         goto loser;
   755     }
   756     if (destValue == NULL) {
   757         myEncrValue = destValue = PORT_ZNew(CRMFEncryptedValue);
   758 	if (destValue == NULL) {
   759 	    goto loser;
   760 	}
   761     }
   763     pubMechType = crmf_get_mechanism_from_public_key(inCAKey);
   764     if (pubMechType == CKM_INVALID_MECHANISM) {
   765         /* XXX I should probably do something here for non-RSA 
   766 	 *     keys that are in certs. (ie DSA)
   767 	 * XXX or at least SET AN ERROR CODE.
   768 	 */
   769         goto loser;
   770     }
   771     slot = inPrivKey->pkcs11Slot; 
   772     PORT_Assert(slot != NULL);
   773     symKeyType = crmf_get_best_privkey_wrap_mechanism(slot);
   774     symKey = PK11_KeyGen(slot, symKeyType, NULL, 0, NULL);
   775     if (symKey == NULL) {
   776         goto loser;
   777     }
   779     wrappedSymKey.data = wrappedSymKeyBits;
   780     wrappedSymKey.len  = MAX_WRAPPED_KEY_LEN;
   781     rv = PK11_PubWrapSymKey(pubMechType, inCAKey, symKey, &wrappedSymKey);
   782     if (rv != SECSuccess) {
   783         goto loser;
   784     }
   785     /* Make the length of the result a Bit String length. */
   786     wrappedSymKey.len <<= 3;
   788     wrappedPrivKey.data = wrappedPrivKeyBits;
   789     wrappedPrivKey.len  = MAX_WRAPPED_KEY_LEN;
   790     iv = crmf_get_iv(symKeyType);
   791     rv = PK11_WrapPrivKey(slot, symKey, inPrivKey, symKeyType, iv, 
   792 			  &wrappedPrivKey, NULL);
   793     PK11_FreeSymKey(symKey);
   794     if (rv != SECSuccess) {
   795         goto loser;
   796     }
   797     /* Make the length of the result a Bit String length. */
   798     wrappedPrivKey.len <<= 3;
   799     rv = crmf_make_bitstring_copy(NULL, 
   800 				  &destValue->encValue, 
   801 				  &wrappedPrivKey);
   802     if (rv != SECSuccess) {
   803         goto loser;
   804     }
   806     rv = crmf_make_bitstring_copy(NULL,
   807 				  &destValue->encSymmKey, 
   808 				  &wrappedSymKey);
   809     if (rv != SECSuccess) {
   810         goto loser;
   811     }
   812     destValue->symmAlg = symmAlg = PORT_ZNew(SECAlgorithmID);
   813     if (symmAlg == NULL) {
   814         goto loser;
   815     }
   817     dummy = SEC_ASN1EncodeItem(NULL, &encodedParam, iv, 
   818                                SEC_ASN1_GET(SEC_OctetStringTemplate));
   819     if (dummy != &encodedParam) {
   820         SECITEM_FreeItem(dummy, PR_TRUE);
   821 	goto loser;
   822     }
   824     symKeyType = crmf_get_non_pad_mechanism(symKeyType);
   825     tag = PK11_MechanismToAlgtag(symKeyType);
   826     rv = SECOID_SetAlgorithmID(NULL, symmAlg, tag, &encodedParam);
   827     if (rv != SECSuccess) {
   828         goto loser;
   829     }
   830     SECITEM_FreeItem(&encodedParam, PR_FALSE);
   831     PORT_Free(wrappedPrivKeyBits);
   832     PORT_Free(wrappedSymKeyBits);
   833     SECITEM_FreeItem(iv, PR_TRUE);
   834     return destValue;
   835  loser:
   836     if (iv != NULL) {
   837 	SECITEM_FreeItem(iv, PR_TRUE);
   838     }
   839     if (myEncrValue != NULL) {
   840         crmf_destroy_encrypted_value(myEncrValue, PR_TRUE);
   841     }
   842     if (wrappedSymKeyBits != NULL) {
   843         PORT_Free(wrappedSymKeyBits);
   844     }
   845     if (wrappedPrivKeyBits != NULL) {
   846         PORT_Free(wrappedPrivKeyBits);
   847     }
   848     if (encodedParam.data != NULL) {
   849 	SECITEM_FreeItem(&encodedParam, PR_FALSE);
   850     }
   851     return NULL;
   852 }
   854 CRMFEncryptedKey*
   855 CRMF_CreateEncryptedKeyWithEncryptedValue (SECKEYPrivateKey *inPrivKey,
   856 					   CERTCertificate  *inCACert)
   857 {
   858     SECKEYPublicKey          *caPubKey = NULL;
   859     CRMFEncryptedKey         *encKey = NULL;
   860     CRMFEncryptedValue       *dummy;
   862     PORT_Assert(inPrivKey != NULL && inCACert != NULL);
   863     if (inPrivKey == NULL || inCACert == NULL) {
   864         return NULL;
   865     }
   867     caPubKey = CERT_ExtractPublicKey(inCACert);
   868     if (caPubKey == NULL) {
   869         goto loser;
   870     }
   872     encKey = PORT_ZNew(CRMFEncryptedKey);
   873     if (encKey == NULL) {
   874         goto loser;
   875     }
   876     dummy = crmf_create_encrypted_value_wrapped_privkey(inPrivKey,
   877 							caPubKey,
   878 					       &encKey->value.encryptedValue);
   879     PORT_Assert(dummy == &encKey->value.encryptedValue);
   880     /* We won't add the der value here, but rather when it 
   881      * becomes part of a certificate request.
   882      */
   883     SECKEY_DestroyPublicKey(caPubKey);
   884     encKey->encKeyChoice = crmfEncryptedValueChoice;
   885     return encKey;
   886  loser:
   887     if (encKey != NULL) {
   888         CRMF_DestroyEncryptedKey(encKey);
   889     }
   890     if (caPubKey != NULL) {
   891         SECKEY_DestroyPublicKey(caPubKey);
   892     }
   893     return NULL;
   894 }
   896 SECStatus
   897 CRMF_DestroyEncryptedKey(CRMFEncryptedKey *inEncrKey)
   898 {
   899     return crmf_destroy_encrypted_key(inEncrKey, PR_TRUE);
   900 }
   902 SECStatus
   903 crmf_copy_pkiarchiveoptions(PLArenaPool           *poolp,
   904 			    CRMFPKIArchiveOptions *destOpt,
   905 			    CRMFPKIArchiveOptions *srcOpt)
   906 {
   907     SECStatus rv;
   908     destOpt->archOption = srcOpt->archOption;
   909     switch (srcOpt->archOption) {
   910     case crmfEncryptedPrivateKey:
   911         rv = crmf_copy_encryptedkey(poolp,
   912 				    &srcOpt->option.encryptedKey,
   913 				    &destOpt->option.encryptedKey);
   914         break;
   915     case crmfKeyGenParameters:
   916     case crmfArchiveRemGenPrivKey:
   917         /* We've got a union, so having a pointer to one is just
   918 	 * like having a pointer to the other one.
   919 	 */
   920         rv = SECITEM_CopyItem(poolp, 
   921 			      &destOpt->option.keyGenParameters,
   922 			      &srcOpt->option.keyGenParameters);
   923 	break;
   924     default:
   925         rv = SECFailure;
   926     }
   927     return rv;
   928 }
   930 static SECStatus
   931 crmf_check_and_adjust_archoption(CRMFControl *inControl)
   932 {
   933     CRMFPKIArchiveOptions *options;
   935     options = &inControl->value.archiveOptions;
   936     if (options->archOption == crmfNoArchiveOptions) {
   937         /* It hasn't been set, so figure it out from the 
   938 	 * der.
   939 	 */
   940         switch (inControl->derValue.data[0] & 0x0f) {
   941 	case 0:
   942 	    options->archOption = crmfEncryptedPrivateKey;
   943 	    break;
   944 	case 1:
   945 	    options->archOption = crmfKeyGenParameters;
   946 	    break;
   947 	case 2:
   948 	    options->archOption = crmfArchiveRemGenPrivKey;
   949 	    break;
   950 	default:
   951 	    /* We've got bad DER.  Return an error. */
   952 	    return SECFailure;
   953 	}
   954     }
   955     return SECSuccess;
   956 }
   958 static const SEC_ASN1Template *
   959 crmf_get_pkiarchive_subtemplate(CRMFControl *inControl)
   960 {
   961     const SEC_ASN1Template *retTemplate;
   962     SECStatus               rv;
   963     /*
   964      * We could be in the process of decoding, in which case the
   965      * archOption field will not be set.  Let's check it and set 
   966      * it accordingly.
   967      */
   969     rv = crmf_check_and_adjust_archoption(inControl);
   970     if (rv != SECSuccess) {
   971         return NULL;
   972     }
   974     switch (inControl->value.archiveOptions.archOption) {
   975     case crmfEncryptedPrivateKey:
   976         retTemplate = CRMFEncryptedKeyWithEncryptedValueTemplate;
   977 	inControl->value.archiveOptions.option.encryptedKey.encKeyChoice =
   978 	  crmfEncryptedValueChoice;
   979 	break;
   980     default:
   981         retTemplate = NULL;
   982     }
   983     return retTemplate;
   984 }
   986 const SEC_ASN1Template*
   987 crmf_get_pkiarchiveoptions_subtemplate(CRMFControl *inControl)
   988 {
   989     const SEC_ASN1Template *retTemplate;
   991     switch (inControl->tag) {
   992     case SEC_OID_PKIX_REGCTRL_REGTOKEN:
   993     case SEC_OID_PKIX_REGCTRL_AUTHENTICATOR:
   994         retTemplate = SEC_ASN1_GET(SEC_UTF8StringTemplate);
   995 	break;
   996     case SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS:
   997         retTemplate = crmf_get_pkiarchive_subtemplate(inControl);
   998 	break;
   999     case SEC_OID_PKIX_REGCTRL_PKIPUBINFO:
  1000     case SEC_OID_PKIX_REGCTRL_OLD_CERT_ID:
  1001     case SEC_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY:
  1002         /* We don't support these controls, so we fail for now.*/
  1003         retTemplate = NULL;
  1004 	break;
  1005     default:
  1006         retTemplate = NULL;
  1008     return retTemplate;
  1011 static SECStatus
  1012 crmf_encode_pkiarchiveoptions(PLArenaPool *poolp, CRMFControl *inControl)
  1014     const SEC_ASN1Template *asn1Template;
  1016     asn1Template = crmf_get_pkiarchiveoptions_subtemplate(inControl);
  1017     /* We've got a union, so passing a pointer to one element of the 
  1018      * union, is the same as passing a pointer to any of the other
  1019      * members of the union.
  1020      */
  1021     SEC_ASN1EncodeItem(poolp, &inControl->derValue,
  1022                        &inControl->value.archiveOptions, asn1Template);
  1024     if (inControl->derValue.data == NULL) {
  1025         goto loser;
  1027     return SECSuccess;
  1028  loser:
  1029     return SECFailure;
  1032 SECStatus
  1033 CRMF_CertRequestSetPKIArchiveOptions(CRMFCertRequest       *inCertReq,
  1034 				     CRMFPKIArchiveOptions *inOptions)
  1036     CRMFControl *newControl;
  1037     PLArenaPool *poolp;
  1038     SECStatus    rv;
  1039     void        *mark;
  1041     PORT_Assert(inCertReq != NULL && inOptions != NULL);
  1042     if (inCertReq == NULL || inOptions == NULL) {
  1043         return SECFailure;
  1045     poolp = inCertReq->poolp;
  1046     mark = PORT_ArenaMark(poolp);
  1047     rv = crmf_add_new_control(inCertReq, 
  1048 			      SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS,
  1049 			      &newControl);
  1050     if (rv != SECSuccess) {
  1051         goto loser;
  1054     rv = crmf_copy_pkiarchiveoptions(poolp, 
  1055 				     &newControl->value.archiveOptions,
  1056 				     inOptions);
  1057     if (rv != SECSuccess) {
  1058         goto loser;
  1061     rv = crmf_encode_pkiarchiveoptions(poolp, newControl); 
  1062     if (rv != SECSuccess) {
  1063         goto loser;
  1065     PORT_ArenaUnmark(poolp, mark);
  1066     return SECSuccess;
  1067  loser:
  1068     PORT_ArenaRelease(poolp, mark);
  1069     return SECFailure;
  1072 static SECStatus
  1073 crmf_destroy_control(CRMFControl *inControl, PRBool freeit)
  1075     PORT_Assert(inControl != NULL);
  1076     if (inControl != NULL) {
  1077         SECITEM_FreeItem(&inControl->derTag, PR_FALSE);
  1078         SECITEM_FreeItem(&inControl->derValue, PR_FALSE);
  1079 	/* None of the other tags require special processing at 
  1080 	 * the moment when freeing because they are not supported,
  1081 	 * but if/when they are, add the necessary routines here.  
  1082 	 * If all controls are supported, then every member of the 
  1083 	 * union inControl->value will have a case that deals with 
  1084 	 * it in the following switch statement.
  1085 	 */
  1086 	switch (inControl->tag) {
  1087 	case SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS:
  1088 	    crmf_destroy_pkiarchiveoptions(&inControl->value.archiveOptions,
  1089 					   PR_FALSE);
  1090 	    break;
  1091         default:
  1092            /* Put this here to get rid of all those annoying warnings.*/
  1093            break;
  1095 	if (freeit) {
  1096 	    PORT_Free(inControl);
  1099     return SECSuccess;
  1102 SECStatus
  1103 CRMF_DestroyControl(CRMFControl *inControl)
  1105     return crmf_destroy_control(inControl, PR_TRUE);
  1108 static SECOidTag
  1109 crmf_controltype_to_tag(CRMFControlType inControlType)
  1111     SECOidTag retVal;
  1113     switch(inControlType) {
  1114     case crmfRegTokenControl:
  1115       retVal = SEC_OID_PKIX_REGCTRL_REGTOKEN; 
  1116       break;
  1117     case crmfAuthenticatorControl:
  1118       retVal = SEC_OID_PKIX_REGCTRL_AUTHENTICATOR;
  1119       break;
  1120     case crmfPKIPublicationInfoControl:
  1121       retVal = SEC_OID_PKIX_REGCTRL_PKIPUBINFO;
  1122       break;
  1123     case crmfPKIArchiveOptionsControl:
  1124       retVal = SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS;
  1125       break;
  1126     case crmfOldCertIDControl:
  1127       retVal = SEC_OID_PKIX_REGCTRL_OLD_CERT_ID;
  1128       break;
  1129     case crmfProtocolEncrKeyControl:
  1130       retVal = SEC_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY;
  1131       break;
  1132     default:
  1133       retVal = SEC_OID_UNKNOWN;
  1134       break;
  1136     return retVal;
  1139 PRBool
  1140 CRMF_CertRequestIsControlPresent(CRMFCertRequest *inCertReq,
  1141 				 CRMFControlType  inControlType)
  1143     SECOidTag controlTag;
  1144     int       i;
  1146     PORT_Assert(inCertReq != NULL);
  1147     if (inCertReq == NULL || inCertReq->controls == NULL) {
  1148         return PR_FALSE;
  1150     controlTag = crmf_controltype_to_tag(inControlType);
  1151     for (i=0; inCertReq->controls[i] != NULL; i++) {
  1152         if (inCertReq->controls[i]->tag == controlTag) {
  1153 	    return PR_TRUE;
  1156     return PR_FALSE;

mercurial