Back to index

lightning-sunbird  0.9+nobinonly
crmfcont.c
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 8 -*-*/
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape security libraries.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "crmf.h"
00039 #include "crmfi.h"
00040 #include "pk11func.h"
00041 #include "keyhi.h"
00042 #include "secoid.h"
00043 
00044 static SECStatus
00045 crmf_modify_control_array (CRMFCertRequest *inCertReq, int count)
00046 {
00047     if (count > 0) {
00048         void *dummy = PORT_Realloc(inCertReq->controls, 
00049                                sizeof(CRMFControl*)*(count+2));
00050        if (dummy == NULL) {
00051            return SECFailure;
00052        }
00053        inCertReq->controls = dummy;
00054     } else {
00055         inCertReq->controls = PORT_ZNewArray(CRMFControl*, 2);
00056     }
00057     return (inCertReq->controls == NULL) ? SECFailure : SECSuccess ;
00058 }
00059 
00060 static SECStatus
00061 crmf_add_new_control(CRMFCertRequest *inCertReq,SECOidTag inTag,
00062                    CRMFControl **destControl)
00063 {
00064     SECOidData  *oidData;
00065     SECStatus    rv;
00066     PRArenaPool *poolp;
00067     int          numControls = 0;
00068     CRMFControl *newControl;
00069     CRMFControl **controls;
00070     void        *mark;
00071 
00072     poolp = inCertReq->poolp;
00073     if (poolp == NULL) {
00074         return SECFailure;
00075     }
00076     mark = PORT_ArenaMark(poolp);
00077     if (inCertReq->controls != NULL) {
00078         while (inCertReq->controls[numControls] != NULL)
00079            numControls++;
00080     }
00081     rv = crmf_modify_control_array(inCertReq, numControls);
00082     if (rv != SECSuccess) {
00083         goto loser;
00084     }
00085     controls = inCertReq->controls;
00086     oidData = SECOID_FindOIDByTag(inTag);
00087     newControl = *destControl = PORT_ArenaZNew(poolp,CRMFControl);
00088     if (newControl == NULL) {
00089         goto loser;
00090     }
00091     rv = SECITEM_CopyItem(poolp, &newControl->derTag, &oidData->oid);
00092     if (rv != SECSuccess) {
00093         goto loser;
00094     }
00095     newControl->tag = inTag;
00096     controls[numControls] = newControl;
00097     controls[numControls+1] = NULL;
00098     PORT_ArenaUnmark(poolp, mark);
00099     return SECSuccess;
00100 
00101  loser:
00102     PORT_ArenaRelease(poolp, mark);
00103     *destControl = NULL;
00104     return SECFailure;
00105                        
00106 }
00107 
00108 SECStatus
00109 crmf_add_secitem_control(CRMFCertRequest *inCertReq, SECItem *value,
00110                       SECOidTag inTag)
00111 {
00112     SECStatus    rv;
00113     CRMFControl *newControl;
00114     void        *mark;
00115 
00116     rv = crmf_add_new_control(inCertReq, inTag, &newControl);
00117     if (rv != SECSuccess) {
00118         return rv;
00119     }
00120     mark = PORT_ArenaMark(inCertReq->poolp);
00121     rv = SECITEM_CopyItem(inCertReq->poolp, &newControl->derValue, value);
00122     if (rv != SECSuccess) {
00123         PORT_ArenaRelease(inCertReq->poolp, mark);
00124        return rv;
00125     }
00126     PORT_ArenaUnmark(inCertReq->poolp, mark);
00127     return SECSuccess;
00128 }
00129 
00130 SECStatus
00131 CRMF_CertRequestSetRegTokenControl(CRMFCertRequest *inCertReq, SECItem *value)
00132 {
00133     return crmf_add_secitem_control(inCertReq, value, 
00134                                 SEC_OID_PKIX_REGCTRL_REGTOKEN);
00135 }
00136 
00137 SECStatus
00138 CRMF_CertRequestSetAuthenticatorControl (CRMFCertRequest *inCertReq, 
00139                                     SECItem         *value)
00140 {
00141     return crmf_add_secitem_control(inCertReq, value, 
00142                                 SEC_OID_PKIX_REGCTRL_AUTHENTICATOR);
00143 }
00144 
00145 SECStatus
00146 crmf_destroy_encrypted_value(CRMFEncryptedValue *inEncrValue, PRBool freeit)
00147 {
00148     if (inEncrValue != NULL) {
00149         if (inEncrValue->intendedAlg) {
00150            SECOID_DestroyAlgorithmID(inEncrValue->intendedAlg, PR_TRUE);
00151            inEncrValue->intendedAlg = NULL;
00152        }
00153        if (inEncrValue->symmAlg) {
00154            SECOID_DestroyAlgorithmID(inEncrValue->symmAlg, PR_TRUE);
00155            inEncrValue->symmAlg = NULL;
00156        }
00157         if (inEncrValue->encSymmKey.data) {
00158            PORT_Free(inEncrValue->encSymmKey.data);
00159            inEncrValue->encSymmKey.data = NULL;
00160        }
00161        if (inEncrValue->keyAlg) {
00162            SECOID_DestroyAlgorithmID(inEncrValue->keyAlg, PR_TRUE);
00163            inEncrValue->keyAlg = NULL;
00164        }
00165        if (inEncrValue->valueHint.data) {
00166            PORT_Free(inEncrValue->valueHint.data);
00167            inEncrValue->valueHint.data = NULL;
00168        }
00169         if (inEncrValue->encValue.data) {
00170            PORT_Free(inEncrValue->encValue.data);
00171            inEncrValue->encValue.data = NULL;
00172        }
00173        if (freeit) {
00174            PORT_Free(inEncrValue);
00175        }
00176     }
00177     return SECSuccess;
00178 }
00179 
00180 SECStatus
00181 CRMF_DestroyEncryptedValue(CRMFEncryptedValue *inEncrValue)
00182 {
00183     return crmf_destroy_encrypted_value(inEncrValue, PR_TRUE);
00184 }
00185 
00186 SECStatus
00187 crmf_copy_encryptedvalue_secalg(PRArenaPool     *poolp,
00188                             SECAlgorithmID  *srcAlgId,
00189                             SECAlgorithmID **destAlgId)
00190 {
00191     SECAlgorithmID *newAlgId;
00192     SECStatus rv;
00193 
00194     newAlgId = (poolp != NULL) ? PORT_ArenaZNew(poolp, SECAlgorithmID) :
00195                                  PORT_ZNew(SECAlgorithmID);
00196     if (newAlgId == NULL) {
00197         return SECFailure;
00198     }
00199     
00200     rv = SECOID_CopyAlgorithmID(poolp, newAlgId, srcAlgId);
00201     if (rv != SECSuccess) {
00202         if (!poolp) {
00203             SECOID_DestroyAlgorithmID(newAlgId, PR_TRUE);
00204         }
00205         return rv;
00206     }
00207     *destAlgId = newAlgId;
00208     
00209     return rv;
00210 }
00211 
00212 SECStatus
00213 crmf_copy_encryptedvalue(PRArenaPool        *poolp,
00214                       CRMFEncryptedValue *srcValue,
00215                       CRMFEncryptedValue *destValue)
00216 {
00217     SECStatus           rv;
00218 
00219     if (srcValue->intendedAlg != NULL) {
00220         rv = crmf_copy_encryptedvalue_secalg(poolp,
00221                                         srcValue->intendedAlg,
00222                                         &destValue->intendedAlg);
00223        if (rv != SECSuccess) {
00224            goto loser;
00225        }
00226     }
00227     if (srcValue->symmAlg != NULL) {
00228         rv = crmf_copy_encryptedvalue_secalg(poolp, 
00229                                         srcValue->symmAlg,
00230                                         &destValue->symmAlg);
00231        if (rv != SECSuccess) {
00232            goto loser;
00233        }
00234     }
00235     if (srcValue->encSymmKey.data != NULL) {
00236         rv = crmf_make_bitstring_copy(poolp, 
00237                                   &destValue->encSymmKey,
00238                                   &srcValue->encSymmKey);
00239        if (rv != SECSuccess) {
00240            goto loser;
00241        }
00242     }
00243     if (srcValue->keyAlg != NULL) {
00244         rv = crmf_copy_encryptedvalue_secalg(poolp,
00245                                         srcValue->keyAlg,
00246                                         &destValue->keyAlg);
00247        if (rv != SECSuccess) {
00248            goto loser;
00249        }
00250     }
00251     if (srcValue->valueHint.data != NULL) {
00252         rv = SECITEM_CopyItem(poolp, 
00253                            &destValue->valueHint,
00254                            &srcValue->valueHint);
00255        if (rv != SECSuccess) {
00256            goto loser;
00257        }
00258     }
00259     if (srcValue->encValue.data != NULL) {
00260         rv = crmf_make_bitstring_copy(poolp,
00261                                   &destValue->encValue,
00262                                   &srcValue->encValue);
00263        if (rv != SECSuccess) {
00264            goto loser;
00265        }
00266     }
00267     return SECSuccess;
00268  loser:
00269     if (poolp == NULL && destValue != NULL) {
00270         crmf_destroy_encrypted_value(destValue, PR_FALSE);
00271     }
00272     return SECFailure;
00273 }
00274 
00275 SECStatus 
00276 crmf_copy_encryptedkey(PRArenaPool       *poolp,
00277                      CRMFEncryptedKey  *srcEncrKey,
00278                      CRMFEncryptedKey  *destEncrKey)
00279 {
00280     SECStatus          rv;
00281     void              *mark = NULL;
00282 
00283     if (poolp != NULL) {
00284         mark = PORT_ArenaMark(poolp);
00285     }
00286 
00287     switch (srcEncrKey->encKeyChoice) {
00288     case crmfEncryptedValueChoice:
00289         rv = crmf_copy_encryptedvalue(poolp, 
00290                                   &srcEncrKey->value.encryptedValue,
00291                                   &destEncrKey->value.encryptedValue);
00292        break;
00293     case crmfEnvelopedDataChoice:
00294         destEncrKey->value.envelopedData = 
00295            SEC_PKCS7CopyContentInfo(srcEncrKey->value.envelopedData);
00296         rv = (destEncrKey->value.envelopedData != NULL) ? SECSuccess:
00297                                                          SECFailure;
00298         break;
00299     default:
00300         rv = SECFailure;
00301     }
00302     if (rv != SECSuccess) {
00303         goto loser;
00304     }
00305     destEncrKey->encKeyChoice = srcEncrKey->encKeyChoice;
00306     if (mark) {
00307        PORT_ArenaUnmark(poolp, mark);
00308     }
00309     return SECSuccess;
00310 
00311  loser:
00312     if (mark) {
00313         PORT_ArenaRelease(poolp, mark);
00314     }
00315     return SECFailure;
00316 }
00317 
00318 CRMFPKIArchiveOptions*
00319 crmf_create_encr_pivkey_option(CRMFEncryptedKey *inEncryptedKey)
00320 {
00321     CRMFPKIArchiveOptions *newArchOpt;
00322     SECStatus              rv;
00323 
00324     newArchOpt = PORT_ZNew(CRMFPKIArchiveOptions);
00325     if (newArchOpt == NULL) {
00326         goto loser;
00327     }
00328 
00329     rv = crmf_copy_encryptedkey(NULL, inEncryptedKey,
00330                             &newArchOpt->option.encryptedKey);
00331     
00332     if (rv != SECSuccess) {
00333       goto loser;
00334     }
00335     newArchOpt->archOption = crmfEncryptedPrivateKey;
00336     return newArchOpt;
00337  loser:
00338     if (newArchOpt != NULL) {
00339         CRMF_DestroyPKIArchiveOptions(newArchOpt);
00340     }
00341     return NULL;
00342 }
00343 
00344 static CRMFPKIArchiveOptions*
00345 crmf_create_keygen_param_option(SECItem *inKeyGenParams)
00346 {
00347     CRMFPKIArchiveOptions *newArchOptions;
00348     SECStatus              rv;
00349 
00350     newArchOptions = PORT_ZNew(CRMFPKIArchiveOptions);
00351     if (newArchOptions == NULL) {
00352         goto loser;
00353     }
00354     newArchOptions->archOption = crmfKeyGenParameters;
00355     rv = SECITEM_CopyItem(NULL, &newArchOptions->option.keyGenParameters,
00356                        inKeyGenParams);
00357     if (rv != SECSuccess) {
00358         goto loser;
00359     }
00360     return newArchOptions;
00361  loser:
00362     if (newArchOptions != NULL) {
00363         CRMF_DestroyPKIArchiveOptions(newArchOptions);
00364     }
00365     return NULL;
00366 }
00367 
00368 static CRMFPKIArchiveOptions*
00369 crmf_create_arch_rem_gen_privkey(PRBool archiveRemGenPrivKey)
00370 {
00371     unsigned char          value;
00372     SECItem               *dummy;
00373     CRMFPKIArchiveOptions *newArchOptions;
00374 
00375     value = (archiveRemGenPrivKey) ? hexTrue : hexFalse;
00376     newArchOptions = PORT_ZNew(CRMFPKIArchiveOptions);
00377     if (newArchOptions == NULL) {
00378         goto loser;
00379     }
00380     dummy = SEC_ASN1EncodeItem(NULL, 
00381                             &newArchOptions->option.archiveRemGenPrivKey,
00382                             &value, SEC_ASN1_GET(SEC_BooleanTemplate));
00383     PORT_Assert (dummy == &newArchOptions->option.archiveRemGenPrivKey);
00384     if (dummy != &newArchOptions->option.archiveRemGenPrivKey) {
00385         SECITEM_FreeItem (dummy, PR_TRUE);
00386        goto loser;
00387     }
00388     newArchOptions->archOption = crmfArchiveRemGenPrivKey;
00389     return newArchOptions;
00390  loser:
00391     if (newArchOptions != NULL) {
00392         CRMF_DestroyPKIArchiveOptions(newArchOptions);
00393     }
00394     return NULL;
00395 }
00396 
00397 CRMFPKIArchiveOptions*
00398 CRMF_CreatePKIArchiveOptions(CRMFPKIArchiveOptionsType inType, void *data)
00399 {
00400     CRMFPKIArchiveOptions* retOptions;
00401 
00402     PORT_Assert(data != NULL);
00403     if (data == NULL) {
00404         return NULL;
00405     }
00406     switch(inType) {
00407     case crmfEncryptedPrivateKey:
00408         retOptions = crmf_create_encr_pivkey_option((CRMFEncryptedKey*)data);
00409        break;
00410     case crmfKeyGenParameters:
00411         retOptions = crmf_create_keygen_param_option((SECItem*)data);
00412        break;
00413     case crmfArchiveRemGenPrivKey:
00414         retOptions = crmf_create_arch_rem_gen_privkey(*(PRBool*)data);
00415        break;
00416     default:
00417         retOptions = NULL;
00418     }
00419     return retOptions;
00420 }
00421 
00422 static SECStatus
00423 crmf_destroy_encrypted_key(CRMFEncryptedKey *inEncrKey, PRBool freeit)
00424 { 
00425     PORT_Assert(inEncrKey != NULL);
00426     if (inEncrKey != NULL) {
00427         switch (inEncrKey->encKeyChoice){
00428        case crmfEncryptedValueChoice:
00429             crmf_destroy_encrypted_value(&inEncrKey->value.encryptedValue, 
00430                                     PR_FALSE);
00431            break;
00432        case crmfEnvelopedDataChoice:
00433            SEC_PKCS7DestroyContentInfo(inEncrKey->value.envelopedData);
00434             break;
00435         default:
00436             break;
00437         }
00438         if (freeit) {
00439             PORT_Free(inEncrKey);
00440         }
00441     }
00442     return SECSuccess;
00443 }
00444 
00445 SECStatus 
00446 crmf_destroy_pkiarchiveoptions(CRMFPKIArchiveOptions *inArchOptions, 
00447                             PRBool                 freeit)
00448 {
00449     PORT_Assert(inArchOptions != NULL);
00450     if (inArchOptions != NULL) {
00451         switch (inArchOptions->archOption) {
00452        case crmfEncryptedPrivateKey:
00453            crmf_destroy_encrypted_key(&inArchOptions->option.encryptedKey,
00454                                    PR_FALSE);
00455            break;
00456        case crmfKeyGenParameters:
00457        case crmfArchiveRemGenPrivKey:
00458            /* This is a union, so having a pointer to one is like
00459             * having a pointer to both.  
00460             */
00461            SECITEM_FreeItem(&inArchOptions->option.keyGenParameters, 
00462                           PR_FALSE);
00463            break;
00464         case crmfNoArchiveOptions:
00465             break;
00466        }
00467        if (freeit) {
00468            PORT_Free(inArchOptions);
00469        }
00470     }
00471     return SECSuccess;
00472 }
00473 
00474 SECStatus
00475 CRMF_DestroyPKIArchiveOptions(CRMFPKIArchiveOptions *inArchOptions) 
00476 {
00477     return crmf_destroy_pkiarchiveoptions(inArchOptions, PR_TRUE);
00478 }
00479 
00480 static CK_MECHANISM_TYPE
00481 crmf_get_non_pad_mechanism(CK_MECHANISM_TYPE type)
00482 {
00483     switch (type) {
00484     case CKM_DES3_CBC_PAD:
00485         return CKM_DES3_CBC;
00486     case CKM_CAST5_CBC_PAD:
00487         return CKM_CAST5_CBC;
00488     case CKM_DES_CBC_PAD:
00489         return CKM_DES_CBC;
00490     case CKM_IDEA_CBC_PAD:
00491         return CKM_IDEA_CBC;
00492     case CKM_CAST3_CBC_PAD:
00493         return CKM_CAST3_CBC;
00494     case CKM_CAST_CBC_PAD:
00495         return CKM_CAST_CBC;
00496     case CKM_RC5_CBC_PAD:
00497         return CKM_RC5_CBC;
00498     case CKM_RC2_CBC_PAD:
00499         return CKM_RC2_CBC;
00500     case CKM_CDMF_CBC_PAD:
00501         return CKM_CDMF_CBC;
00502     }
00503     return type;
00504 }
00505 
00506 static CK_MECHANISM_TYPE
00507 crmf_get_pad_mech_from_tag(SECOidTag oidTag)
00508 {
00509     CK_MECHANISM_TYPE  mechType;
00510     SECOidData        *oidData;
00511 
00512     oidData = SECOID_FindOIDByTag(oidTag);
00513     mechType = (CK_MECHANISM_TYPE)oidData->mechanism;
00514     return PK11_GetPadMechanism(mechType);
00515 }
00516 
00517 static CK_MECHANISM_TYPE
00518 crmf_get_best_privkey_wrap_mechanism(PK11SlotInfo *slot) 
00519 {
00520     CK_MECHANISM_TYPE privKeyPadMechs[] = { CKM_DES3_CBC_PAD,
00521                                        CKM_CAST5_CBC_PAD,
00522                                        CKM_DES_CBC_PAD,
00523                                        CKM_IDEA_CBC_PAD,
00524                                        CKM_CAST3_CBC_PAD,
00525                                        CKM_CAST_CBC_PAD,
00526                                        CKM_RC5_CBC_PAD,
00527                                        CKM_RC2_CBC_PAD,
00528                                        CKM_CDMF_CBC_PAD };
00529     int mechCount = sizeof(privKeyPadMechs)/sizeof(privKeyPadMechs[0]);
00530     int i;
00531 
00532     for (i=0; i < mechCount; i++) {
00533         if (PK11_DoesMechanism(slot, privKeyPadMechs[i])) {
00534            return privKeyPadMechs[i];
00535        }
00536     }
00537     return CKM_INVALID_MECHANISM;
00538 }
00539 
00540 CK_MECHANISM_TYPE
00541 CRMF_GetBestWrapPadMechanism(PK11SlotInfo *slot)
00542 {
00543     return crmf_get_best_privkey_wrap_mechanism(slot);
00544 }
00545 
00546 static SECItem*
00547 crmf_get_iv(CK_MECHANISM_TYPE mechType)
00548 {
00549     int        iv_size = PK11_GetIVLength(mechType);
00550     SECItem   *iv;
00551     SECStatus  rv; 
00552 
00553     iv = PORT_ZNew(SECItem);
00554     if (iv == NULL) {
00555         return NULL;
00556     }
00557     if (iv_size == 0) {
00558         iv->data = NULL;
00559        iv->len  = 0;
00560        return iv;
00561     }
00562     iv->data = PORT_NewArray(unsigned char, iv_size);
00563     if (iv->data == NULL) {
00564         iv->len = 0;
00565        return iv;
00566     }
00567     iv->len = iv_size;
00568     rv = PK11_GenerateRandom(iv->data, iv->len);
00569     if (rv != SECSuccess) {
00570         PORT_Free(iv->data);
00571        iv->data = NULL;
00572        iv->len  = 0;
00573     }
00574     return iv;
00575 }
00576 
00577 SECItem*
00578 CRMF_GetIVFromMechanism(CK_MECHANISM_TYPE mechType)
00579 {
00580     return crmf_get_iv(mechType);
00581 }
00582 
00583 CK_MECHANISM_TYPE
00584 crmf_get_mechanism_from_public_key(SECKEYPublicKey *inPubKey)
00585 {
00586     CERTSubjectPublicKeyInfo *spki = NULL;
00587     SECOidTag                 tag;
00588     
00589 
00590     spki = SECKEY_CreateSubjectPublicKeyInfo(inPubKey);
00591     if (spki == NULL) {
00592         return CKM_INVALID_MECHANISM;
00593     }
00594     tag = SECOID_FindOIDTag(&spki->algorithm.algorithm);
00595     SECKEY_DestroySubjectPublicKeyInfo(spki);
00596     spki = NULL;
00597     return PK11_AlgtagToMechanism(tag);
00598 }
00599 
00600 SECItem*
00601 crmf_get_public_value(SECKEYPublicKey *pubKey, SECItem *dest)
00602 {
00603     SECItem *src;
00604 
00605     switch(pubKey->keyType) {
00606     case dsaKey:
00607        src =  &pubKey->u.dsa.publicValue;
00608        break;
00609     case rsaKey:
00610        src =  &pubKey->u.rsa.modulus;
00611        break;
00612     case dhKey:
00613        src =  &pubKey->u.dh.publicValue;
00614        break;
00615     default:
00616        src = NULL;
00617        break;
00618     }
00619     if (!src) {
00620        PORT_SetError(SEC_ERROR_INVALID_ARGS);
00621        return NULL;
00622     }
00623 
00624     if (dest != NULL) {
00625        SECStatus rv = SECITEM_CopyItem(NULL, dest, src);
00626        if (rv != SECSuccess) {
00627            dest = NULL;
00628        }
00629     } else {
00630         dest = SECITEM_ArenaDupItem(NULL, src);
00631     }
00632     return dest;
00633 }
00634 
00635 static SECItem*
00636 crmf_decode_params(SECItem *inParams)
00637 {
00638     SECItem     *params;
00639     SECStatus    rv      = SECFailure;
00640     PRArenaPool *poolp;
00641 
00642     poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
00643     if (poolp == NULL) {
00644         return NULL;
00645     }
00646     
00647     params = PORT_ArenaZNew(poolp, SECItem);
00648     if (params) {
00649        rv = SEC_ASN1DecodeItem(poolp, params, 
00650                             SEC_ASN1_GET(SEC_OctetStringTemplate),
00651                             inParams);
00652     }
00653     params = (rv == SECSuccess) ? SECITEM_ArenaDupItem(NULL, params) : NULL;
00654     PORT_FreeArena(poolp, PR_FALSE);
00655     return params;
00656 }
00657 
00658 int
00659 crmf_get_key_size_from_mech(CK_MECHANISM_TYPE mechType)
00660 {
00661     CK_MECHANISM_TYPE keyGen = PK11_GetKeyGen(mechType);
00662 
00663     switch (keyGen) {
00664     case CKM_CDMF_KEY_GEN:
00665     case CKM_DES_KEY_GEN:
00666         return 8;
00667     case CKM_DES2_KEY_GEN:
00668        return 16;
00669     case CKM_DES3_KEY_GEN:
00670        return 24;
00671     }
00672     return 0;
00673 }
00674 
00675 SECStatus
00676 crmf_encrypted_value_unwrap_priv_key(PRArenaPool        *poolp,
00677                                  CRMFEncryptedValue *encValue,
00678                                  SECKEYPrivateKey   *privKey,
00679                                  SECKEYPublicKey    *newPubKey,
00680                                  SECItem            *nickname,
00681                                  PK11SlotInfo       *slot,
00682                                  unsigned char       keyUsage,
00683                                  SECKEYPrivateKey  **unWrappedKey,
00684                                  void               *wincx)
00685 {
00686     PK11SymKey        *wrappingKey = NULL;
00687     CK_MECHANISM_TYPE  wrapMechType;
00688     SECOidTag          oidTag;
00689     SECItem           *params = NULL, *publicValue = NULL;
00690     int                keySize, origLen;
00691     CK_KEY_TYPE        keyType;
00692     CK_ATTRIBUTE_TYPE *usage = NULL;
00693     CK_ATTRIBUTE_TYPE rsaUsage[] = {
00694       CKA_UNWRAP, CKA_DECRYPT, CKA_SIGN, CKA_SIGN_RECOVER };
00695     CK_ATTRIBUTE_TYPE dsaUsage[] = { CKA_SIGN };
00696     CK_ATTRIBUTE_TYPE dhUsage[] = { CKA_DERIVE };
00697     int usageCount = 0;
00698 
00699     oidTag = SECOID_GetAlgorithmTag(encValue->symmAlg);
00700     wrapMechType = crmf_get_pad_mech_from_tag(oidTag);
00701     keySize = crmf_get_key_size_from_mech(wrapMechType);
00702     wrappingKey = PK11_PubUnwrapSymKey(privKey, &encValue->encSymmKey, 
00703                                    wrapMechType, CKA_UNWRAP, keySize);
00704     if (wrappingKey == NULL) {
00705         goto loser;
00706     }/* Make the length a byte length instead of bit length*/
00707     params = (encValue->symmAlg != NULL) ? 
00708               crmf_decode_params(&encValue->symmAlg->parameters) : NULL;
00709     origLen = encValue->encValue.len;
00710     encValue->encValue.len = CRMF_BITS_TO_BYTES(origLen);
00711     publicValue = crmf_get_public_value(newPubKey, NULL);
00712     switch(newPubKey->keyType) {
00713     default:
00714     case rsaKey:
00715         keyType = CKK_RSA;
00716         switch  (keyUsage & (KU_KEY_ENCIPHERMENT|KU_DIGITAL_SIGNATURE)) {
00717         case KU_KEY_ENCIPHERMENT:
00718             usage = rsaUsage;
00719             usageCount = 2;
00720             break;
00721         case KU_DIGITAL_SIGNATURE:
00722             usage = &rsaUsage[2];
00723             usageCount = 2;
00724             break;
00725         case KU_KEY_ENCIPHERMENT|KU_DIGITAL_SIGNATURE:
00726         case 0: /* default to everything */
00727             usage = rsaUsage;
00728             usageCount = 4;
00729             break;
00730         }
00731        break;
00732     case dhKey:
00733         keyType = CKK_DH;
00734         usage = dhUsage;
00735         usageCount = sizeof(dhUsage)/sizeof(dhUsage[0]);
00736         break;
00737     case dsaKey:
00738         keyType = CKK_DSA;
00739         usage = dsaUsage;
00740         usageCount = sizeof(dsaUsage)/sizeof(dsaUsage[0]);
00741         break;
00742     }
00743     PORT_Assert(usage != NULL);
00744     PORT_Assert(usageCount != 0);
00745     *unWrappedKey = PK11_UnwrapPrivKey(slot, wrappingKey, wrapMechType, params,
00746                                    &encValue->encValue, nickname,
00747                                    publicValue, PR_TRUE,PR_TRUE, 
00748                                    keyType, usage, usageCount, wincx);
00749     encValue->encValue.len = origLen;
00750     if (*unWrappedKey == NULL) {
00751         goto loser;
00752     }
00753     SECITEM_FreeItem (publicValue, PR_TRUE);
00754     if (params!= NULL) {
00755         SECITEM_FreeItem(params, PR_TRUE);
00756     } 
00757     PK11_FreeSymKey(wrappingKey);
00758     return SECSuccess;
00759  loser:
00760     *unWrappedKey = NULL;
00761     return SECFailure;
00762 }
00763 
00764 CRMFEncryptedValue *
00765 crmf_create_encrypted_value_wrapped_privkey(SECKEYPrivateKey   *inPrivKey,
00766                                        SECKEYPublicKey    *inCAKey,
00767                                        CRMFEncryptedValue *destValue)
00768 {
00769     SECItem                   wrappedPrivKey, wrappedSymKey;
00770     SECItem                   encodedParam, *dummy;
00771     SECStatus                 rv;
00772     CK_MECHANISM_TYPE         pubMechType, symKeyType;
00773     unsigned char            *wrappedSymKeyBits;
00774     unsigned char            *wrappedPrivKeyBits;
00775     SECItem                  *iv = NULL;
00776     SECOidTag                 tag;
00777     PK11SymKey               *symKey;
00778     PK11SlotInfo             *slot;
00779     SECAlgorithmID           *symmAlg;
00780     CRMFEncryptedValue       *myEncrValue = NULL;
00781 
00782     encodedParam.data = NULL;
00783     wrappedSymKeyBits  = PORT_NewArray(unsigned char, MAX_WRAPPED_KEY_LEN);
00784     wrappedPrivKeyBits = PORT_NewArray(unsigned char, MAX_WRAPPED_KEY_LEN);
00785     if (wrappedSymKeyBits == NULL || wrappedPrivKeyBits == NULL) {
00786         goto loser;
00787     }
00788     if (destValue == NULL) {
00789         myEncrValue = destValue = PORT_ZNew(CRMFEncryptedValue);
00790        if (destValue == NULL) {
00791            goto loser;
00792        }
00793     }
00794 
00795     pubMechType = crmf_get_mechanism_from_public_key(inCAKey);
00796     if (pubMechType == CKM_INVALID_MECHANISM) {
00797         /* XXX I should probably do something here for non-RSA 
00798         *     keys that are in certs. (ie DSA)
00799         * XXX or at least SET AN ERROR CODE.
00800         */
00801         goto loser;
00802     }
00803     slot = inPrivKey->pkcs11Slot; 
00804     PORT_Assert(slot != NULL);
00805     symKeyType = crmf_get_best_privkey_wrap_mechanism(slot);
00806     symKey = PK11_KeyGen(slot, symKeyType, NULL, 0, NULL);
00807     if (symKey == NULL) {
00808         goto loser;
00809     }
00810 
00811     wrappedSymKey.data = wrappedSymKeyBits;
00812     wrappedSymKey.len  = MAX_WRAPPED_KEY_LEN;
00813     rv = PK11_PubWrapSymKey(pubMechType, inCAKey, symKey, &wrappedSymKey);
00814     if (rv != SECSuccess) {
00815         goto loser;
00816     }
00817     /* Make the length of the result a Bit String length. */
00818     wrappedSymKey.len <<= 3;
00819 
00820     wrappedPrivKey.data = wrappedPrivKeyBits;
00821     wrappedPrivKey.len  = MAX_WRAPPED_KEY_LEN;
00822     iv = crmf_get_iv(symKeyType);
00823     rv = PK11_WrapPrivKey(slot, symKey, inPrivKey, symKeyType, iv, 
00824                        &wrappedPrivKey, NULL);
00825     PK11_FreeSymKey(symKey);
00826     if (rv != SECSuccess) {
00827         goto loser;
00828     }
00829     /* Make the length of the result a Bit String length. */
00830     wrappedPrivKey.len <<= 3;
00831     rv = crmf_make_bitstring_copy(NULL, 
00832                               &destValue->encValue, 
00833                               &wrappedPrivKey);
00834     if (rv != SECSuccess) {
00835         goto loser;
00836     }
00837 
00838     rv = crmf_make_bitstring_copy(NULL,
00839                               &destValue->encSymmKey, 
00840                               &wrappedSymKey);
00841     if (rv != SECSuccess) {
00842         goto loser;
00843     }
00844     destValue->symmAlg = symmAlg = PORT_ZNew(SECAlgorithmID);
00845     if (symmAlg == NULL) {
00846         goto loser;
00847     }
00848 
00849     dummy = SEC_ASN1EncodeItem(NULL, &encodedParam, iv, 
00850                                SEC_ASN1_GET(SEC_OctetStringTemplate));
00851     if (dummy != &encodedParam) {
00852         SECITEM_FreeItem(dummy, PR_TRUE);
00853        goto loser;
00854     }
00855 
00856     symKeyType = crmf_get_non_pad_mechanism(symKeyType);
00857     tag = PK11_MechanismToAlgtag(symKeyType);
00858     rv = SECOID_SetAlgorithmID(NULL, symmAlg, tag, &encodedParam);
00859     if (rv != SECSuccess) {
00860         goto loser;
00861     }
00862     SECITEM_FreeItem(&encodedParam, PR_FALSE);
00863     PORT_Free(wrappedPrivKeyBits);
00864     PORT_Free(wrappedSymKeyBits);
00865     SECITEM_FreeItem(iv, PR_TRUE);
00866     return destValue;
00867  loser:
00868     if (iv != NULL) {
00869        SECITEM_FreeItem(iv, PR_TRUE);
00870     }
00871     if (myEncrValue != NULL) {
00872         crmf_destroy_encrypted_value(myEncrValue, PR_TRUE);
00873     }
00874     if (wrappedSymKeyBits != NULL) {
00875         PORT_Free(wrappedSymKeyBits);
00876     }
00877     if (wrappedPrivKeyBits != NULL) {
00878         PORT_Free(wrappedPrivKeyBits);
00879     }
00880     if (encodedParam.data != NULL) {
00881        SECITEM_FreeItem(&encodedParam, PR_FALSE);
00882     }
00883     return NULL;
00884 }
00885 
00886 CRMFEncryptedKey*
00887 CRMF_CreateEncryptedKeyWithEncryptedValue (SECKEYPrivateKey *inPrivKey,
00888                                       CERTCertificate  *inCACert)
00889 {
00890     SECKEYPublicKey          *caPubKey = NULL;
00891     CRMFEncryptedKey         *encKey = NULL;
00892     CRMFEncryptedValue       *dummy;
00893 
00894     PORT_Assert(inPrivKey != NULL && inCACert != NULL);
00895     if (inPrivKey == NULL || inCACert == NULL) {
00896         return NULL;
00897     }
00898 
00899     caPubKey = CERT_ExtractPublicKey(inCACert);
00900     if (caPubKey == NULL) {
00901         goto loser;
00902     }
00903 
00904     encKey = PORT_ZNew(CRMFEncryptedKey);
00905     if (encKey == NULL) {
00906         goto loser;
00907     }
00908     dummy = crmf_create_encrypted_value_wrapped_privkey(inPrivKey,
00909                                                  caPubKey,
00910                                           &encKey->value.encryptedValue);
00911     PORT_Assert(dummy == &encKey->value.encryptedValue);
00912     /* We won't add the der value here, but rather when it 
00913      * becomes part of a certificate request.
00914      */
00915     SECKEY_DestroyPublicKey(caPubKey);
00916     encKey->encKeyChoice = crmfEncryptedValueChoice;
00917     return encKey;
00918  loser:
00919     if (encKey != NULL) {
00920         CRMF_DestroyEncryptedKey(encKey);
00921     }
00922     if (caPubKey != NULL) {
00923         SECKEY_DestroyPublicKey(caPubKey);
00924     }
00925     return NULL;
00926 }
00927 
00928 SECStatus
00929 CRMF_DestroyEncryptedKey(CRMFEncryptedKey *inEncrKey)
00930 {
00931     return crmf_destroy_encrypted_key(inEncrKey, PR_TRUE);
00932 }
00933 
00934 SECStatus
00935 crmf_copy_pkiarchiveoptions(PRArenaPool           *poolp,
00936                          CRMFPKIArchiveOptions *destOpt,
00937                          CRMFPKIArchiveOptions *srcOpt)
00938 {
00939     SECStatus rv;
00940     destOpt->archOption = srcOpt->archOption;
00941     switch (srcOpt->archOption) {
00942     case crmfEncryptedPrivateKey:
00943         rv = crmf_copy_encryptedkey(poolp,
00944                                 &srcOpt->option.encryptedKey,
00945                                 &destOpt->option.encryptedKey);
00946         break;
00947     case crmfKeyGenParameters:
00948     case crmfArchiveRemGenPrivKey:
00949         /* We've got a union, so having a pointer to one is just
00950         * like having a pointer to the other one.
00951         */
00952         rv = SECITEM_CopyItem(poolp, 
00953                            &destOpt->option.keyGenParameters,
00954                            &srcOpt->option.keyGenParameters);
00955        break;
00956     default:
00957         rv = SECFailure;
00958     }
00959     return rv;
00960 }
00961 
00962 static SECStatus
00963 crmf_check_and_adjust_archoption(CRMFControl *inControl)
00964 {
00965     CRMFPKIArchiveOptions *options;
00966 
00967     options = &inControl->value.archiveOptions;
00968     if (options->archOption == crmfNoArchiveOptions) {
00969         /* It hasn't been set, so figure it out from the 
00970         * der.
00971         */
00972         switch (inControl->derValue.data[0] & 0x0f) {
00973        case 0:
00974            options->archOption = crmfEncryptedPrivateKey;
00975            break;
00976        case 1:
00977            options->archOption = crmfKeyGenParameters;
00978            break;
00979        case 2:
00980            options->archOption = crmfArchiveRemGenPrivKey;
00981            break;
00982        default:
00983            /* We've got bad DER.  Return an error. */
00984            return SECFailure;
00985        }
00986     }
00987     return SECSuccess;
00988 }
00989 
00990 static const SEC_ASN1Template *
00991 crmf_get_pkiarchive_subtemplate(CRMFControl *inControl)
00992 {
00993     const SEC_ASN1Template *retTemplate;
00994     SECStatus               rv;
00995     /*
00996      * We could be in the process of decoding, in which case the
00997      * archOption field will not be set.  Let's check it and set 
00998      * it accordingly.
00999      */
01000 
01001     rv = crmf_check_and_adjust_archoption(inControl);
01002     if (rv != SECSuccess) {
01003         return NULL;
01004     }
01005 
01006     switch (inControl->value.archiveOptions.archOption) {
01007     case crmfEncryptedPrivateKey:
01008         retTemplate = CRMFEncryptedKeyWithEncryptedValueTemplate;
01009        inControl->value.archiveOptions.option.encryptedKey.encKeyChoice =
01010          crmfEncryptedValueChoice;
01011        break;
01012     default:
01013         retTemplate = NULL;
01014     }
01015     return retTemplate;
01016 }
01017 
01018 const SEC_ASN1Template*
01019 crmf_get_pkiarchiveoptions_subtemplate(CRMFControl *inControl)
01020 {
01021     const SEC_ASN1Template *retTemplate;
01022 
01023     switch (inControl->tag) {
01024     case SEC_OID_PKIX_REGCTRL_REGTOKEN:
01025     case SEC_OID_PKIX_REGCTRL_AUTHENTICATOR:
01026         retTemplate = SEC_ASN1_GET(SEC_UTF8StringTemplate);
01027        break;
01028     case SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS:
01029         retTemplate = crmf_get_pkiarchive_subtemplate(inControl);
01030        break;
01031     case SEC_OID_PKIX_REGCTRL_PKIPUBINFO:
01032     case SEC_OID_PKIX_REGCTRL_OLD_CERT_ID:
01033     case SEC_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY:
01034         /* We don't support these controls, so we fail for now.*/
01035         retTemplate = NULL;
01036        break;
01037     default:
01038         retTemplate = NULL;
01039     }
01040     return retTemplate;
01041 }
01042 
01043 static SECStatus
01044 crmf_encode_pkiarchiveoptions(PRArenaPool *poolp, CRMFControl *inControl)
01045 {
01046     const SEC_ASN1Template *asn1Template;
01047 
01048     asn1Template = crmf_get_pkiarchiveoptions_subtemplate(inControl);
01049     /* We've got a union, so passing a pointer to one element of the 
01050      * union, is the same as passing a pointer to any of the other
01051      * members of the union.
01052      */
01053     SEC_ASN1EncodeItem(poolp, &inControl->derValue,
01054                        &inControl->value.archiveOptions, asn1Template);
01055 
01056     if (inControl->derValue.data == NULL) {
01057         goto loser;
01058     }
01059     return SECSuccess;
01060  loser:
01061     return SECFailure;
01062 }
01063 
01064 SECStatus
01065 CRMF_CertRequestSetPKIArchiveOptions(CRMFCertRequest       *inCertReq,
01066                                  CRMFPKIArchiveOptions *inOptions)
01067 {
01068     CRMFControl *newControl;
01069     PRArenaPool *poolp;
01070     SECStatus    rv;
01071     void        *mark;
01072     
01073     PORT_Assert(inCertReq != NULL && inOptions != NULL);
01074     if (inCertReq == NULL || inOptions == NULL) {
01075         return SECFailure;
01076     }
01077     poolp = inCertReq->poolp;
01078     mark = PORT_ArenaMark(poolp);
01079     rv = crmf_add_new_control(inCertReq, 
01080                            SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS,
01081                            &newControl);
01082     if (rv != SECSuccess) {
01083         goto loser;
01084     }
01085 
01086     rv = crmf_copy_pkiarchiveoptions(poolp, 
01087                                  &newControl->value.archiveOptions,
01088                                  inOptions);
01089     if (rv != SECSuccess) {
01090         goto loser;
01091     }
01092 
01093     rv = crmf_encode_pkiarchiveoptions(poolp, newControl); 
01094     if (rv != SECSuccess) {
01095         goto loser;
01096     }
01097     PORT_ArenaUnmark(poolp, mark);
01098     return SECSuccess;
01099  loser:
01100     PORT_ArenaRelease(poolp, mark);
01101     return SECFailure;
01102 }
01103 
01104 SECStatus
01105 crmf_destroy_control(CRMFControl *inControl, PRBool freeit)
01106 {
01107     PORT_Assert(inControl != NULL);
01108     if (inControl != NULL) {
01109         SECITEM_FreeItem(&inControl->derTag, PR_FALSE);
01110         SECITEM_FreeItem(&inControl->derValue, PR_FALSE);
01111        /* None of the other tags require special processing at 
01112         * the moment when freeing because they are not supported,
01113         * but if/when they are, add the necessary routines here.  
01114         * If all controls are supported, then every member of the 
01115         * union inControl->value will have a case that deals with 
01116         * it in the following switch statement.
01117         */
01118        switch (inControl->tag) {
01119        case SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS:
01120            crmf_destroy_pkiarchiveoptions(&inControl->value.archiveOptions,
01121                                       PR_FALSE);
01122            break;
01123         default:
01124            /* Put this here to get rid of all those annoying warnings.*/
01125            break;
01126        }
01127        if (freeit) {
01128            PORT_Free(inControl);
01129        }
01130     }
01131     return SECSuccess;
01132 }
01133 
01134 SECStatus
01135 CRMF_DestroyControl(CRMFControl *inControl)
01136 {
01137     return crmf_destroy_control(inControl, PR_TRUE);
01138 }
01139 
01140 static SECOidTag
01141 crmf_controltype_to_tag(CRMFControlType inControlType)
01142 {
01143     SECOidTag retVal;
01144 
01145     switch(inControlType) {
01146     case crmfRegTokenControl:
01147       retVal = SEC_OID_PKIX_REGCTRL_REGTOKEN; 
01148       break;
01149     case crmfAuthenticatorControl:
01150       retVal = SEC_OID_PKIX_REGCTRL_AUTHENTICATOR;
01151       break;
01152     case crmfPKIPublicationInfoControl:
01153       retVal = SEC_OID_PKIX_REGCTRL_PKIPUBINFO;
01154       break;
01155     case crmfPKIArchiveOptionsControl:
01156       retVal = SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS;
01157       break;
01158     case crmfOldCertIDControl:
01159       retVal = SEC_OID_PKIX_REGCTRL_OLD_CERT_ID;
01160       break;
01161     case crmfProtocolEncrKeyControl:
01162       retVal = SEC_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY;
01163       break;
01164     default:
01165       retVal = SEC_OID_UNKNOWN;
01166       break;
01167     }
01168     return retVal;
01169 }
01170 
01171 PRBool
01172 CRMF_CertRequestIsControlPresent(CRMFCertRequest *inCertReq,
01173                              CRMFControlType  inControlType)
01174 {
01175     SECOidTag controlTag;
01176     int       i;
01177 
01178     PORT_Assert(inCertReq != NULL);
01179     if (inCertReq == NULL || inCertReq->controls == NULL) {
01180         return PR_FALSE;
01181     }
01182     controlTag = crmf_controltype_to_tag(inControlType);
01183     for (i=0; inCertReq->controls[i] != NULL; i++) {
01184         if (inCertReq->controls[i]->tag == controlTag) {
01185            return PR_TRUE;
01186        }
01187     }
01188     return PR_FALSE;
01189 }
01190