Back to index

lightning-sunbird  0.9+nobinonly
cmsencdata.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 /*
00038  * CMS encryptedData methods.
00039  *
00040  * $Id: cmsencdata.c,v 1.8 2005/10/03 22:01:57 relyea%netscape.com Exp $
00041  */
00042 
00043 #include "cmslocal.h"
00044 
00045 #include "key.h"
00046 #include "secasn1.h"
00047 #include "secitem.h"
00048 #include "secoid.h"
00049 #include "pk11func.h"
00050 #include "prtime.h"
00051 #include "secerr.h"
00052 #include "secpkcs5.h"
00053 
00054 /*
00055  * NSS_CMSEncryptedData_Create - create an empty encryptedData object.
00056  *
00057  * "algorithm" specifies the bulk encryption algorithm to use.
00058  * "keysize" is the key size.
00059  * 
00060  * An error results in a return value of NULL and an error set.
00061  * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
00062  */
00063 NSSCMSEncryptedData *
00064 NSS_CMSEncryptedData_Create(NSSCMSMessage *cmsg, SECOidTag algorithm, int keysize)
00065 {
00066     void *mark;
00067     NSSCMSEncryptedData *encd;
00068     PLArenaPool *poolp;
00069     SECAlgorithmID *pbe_algid;
00070     SECStatus rv;
00071 
00072     poolp = cmsg->poolp;
00073 
00074     mark = PORT_ArenaMark(poolp);
00075 
00076     encd = (NSSCMSEncryptedData *)PORT_ArenaZAlloc(poolp, sizeof(NSSCMSEncryptedData));
00077     if (encd == NULL)
00078        goto loser;
00079 
00080     encd->cmsg = cmsg;
00081 
00082     /* version is set in NSS_CMSEncryptedData_Encode_BeforeStart() */
00083 
00084     switch (algorithm) {
00085     /* XXX hmmm... hardcoded algorithms? */
00086     case SEC_OID_RC2_CBC:
00087     case SEC_OID_DES_EDE3_CBC:
00088     case SEC_OID_DES_CBC:
00089        rv = NSS_CMSContentInfo_SetContentEncAlg(poolp, &(encd->contentInfo), algorithm, NULL, keysize);
00090        break;
00091     default:
00092        /* Assume password-based-encryption.  At least, try that. */
00093        pbe_algid = PK11_CreatePBEAlgorithmID(algorithm, 1, NULL);
00094        if (pbe_algid == NULL) {
00095            rv = SECFailure;
00096            break;
00097        }
00098        rv = NSS_CMSContentInfo_SetContentEncAlgID(poolp, &(encd->contentInfo), pbe_algid, keysize);
00099        SECOID_DestroyAlgorithmID (pbe_algid, PR_TRUE);
00100        break;
00101     }
00102     if (rv != SECSuccess)
00103        goto loser;
00104 
00105     PORT_ArenaUnmark(poolp, mark);
00106     return encd;
00107 
00108 loser:
00109     PORT_ArenaRelease(poolp, mark);
00110     return NULL;
00111 }
00112 
00113 /*
00114  * NSS_CMSEncryptedData_Destroy - destroy an encryptedData object
00115  */
00116 void
00117 NSS_CMSEncryptedData_Destroy(NSSCMSEncryptedData *encd)
00118 {
00119     /* everything's in a pool, so don't worry about the storage */
00120     NSS_CMSContentInfo_Destroy(&(encd->contentInfo));
00121     return;
00122 }
00123 
00124 /*
00125  * NSS_CMSEncryptedData_GetContentInfo - return pointer to encryptedData object's contentInfo
00126  */
00127 NSSCMSContentInfo *
00128 NSS_CMSEncryptedData_GetContentInfo(NSSCMSEncryptedData *encd)
00129 {
00130     return &(encd->contentInfo);
00131 }
00132 
00133 /*
00134  * NSS_CMSEncryptedData_Encode_BeforeStart - do all the necessary things to a EncryptedData
00135  *     before encoding begins.
00136  *
00137  * In particular:
00138  *  - set the correct version value.
00139  *  - get the encryption key
00140  */
00141 SECStatus
00142 NSS_CMSEncryptedData_Encode_BeforeStart(NSSCMSEncryptedData *encd)
00143 {
00144     int version;
00145     PK11SymKey *bulkkey = NULL;
00146     SECItem *dummy;
00147     NSSCMSContentInfo *cinfo = &(encd->contentInfo);
00148 
00149     if (NSS_CMSArray_IsEmpty((void **)encd->unprotectedAttr))
00150        version = NSS_CMS_ENCRYPTED_DATA_VERSION;
00151     else
00152        version = NSS_CMS_ENCRYPTED_DATA_VERSION_UPATTR;
00153     
00154     dummy = SEC_ASN1EncodeInteger (encd->cmsg->poolp, &(encd->version), version);
00155     if (dummy == NULL)
00156        return SECFailure;
00157 
00158     /* now get content encryption key (bulk key) by using our cmsg callback */
00159     if (encd->cmsg->decrypt_key_cb)
00160        bulkkey = (*encd->cmsg->decrypt_key_cb)(encd->cmsg->decrypt_key_cb_arg, 
00161                   NSS_CMSContentInfo_GetContentEncAlg(cinfo));
00162     if (bulkkey == NULL)
00163        return SECFailure;
00164 
00165     /* store the bulk key in the contentInfo so that the encoder can find it */
00166     NSS_CMSContentInfo_SetBulkKey(cinfo, bulkkey);
00167     PK11_FreeSymKey (bulkkey);
00168 
00169     return SECSuccess;
00170 }
00171 
00172 /*
00173  * NSS_CMSEncryptedData_Encode_BeforeData - set up encryption
00174  */
00175 SECStatus
00176 NSS_CMSEncryptedData_Encode_BeforeData(NSSCMSEncryptedData *encd)
00177 {
00178     NSSCMSContentInfo *cinfo;
00179     PK11SymKey *bulkkey;
00180     SECAlgorithmID *algid;
00181 
00182     cinfo = &(encd->contentInfo);
00183 
00184     /* find bulkkey and algorithm - must have been set by NSS_CMSEncryptedData_Encode_BeforeStart */
00185     bulkkey = NSS_CMSContentInfo_GetBulkKey(cinfo);
00186     if (bulkkey == NULL)
00187        return SECFailure;
00188     algid = NSS_CMSContentInfo_GetContentEncAlg(cinfo);
00189     if (algid == NULL)
00190        return SECFailure;
00191 
00192     /* this may modify algid (with IVs generated in a token).
00193      * it is therefore essential that algid is a pointer to the "real" contentEncAlg,
00194      * not just to a copy */
00195     cinfo->ciphcx = NSS_CMSCipherContext_StartEncrypt(encd->cmsg->poolp, bulkkey, algid);
00196     PK11_FreeSymKey(bulkkey);
00197     if (cinfo->ciphcx == NULL)
00198        return SECFailure;
00199 
00200     return SECSuccess;
00201 }
00202 
00203 /*
00204  * NSS_CMSEncryptedData_Encode_AfterData - finalize this encryptedData for encoding
00205  */
00206 SECStatus
00207 NSS_CMSEncryptedData_Encode_AfterData(NSSCMSEncryptedData *encd)
00208 {
00209     if (encd->contentInfo.ciphcx) {
00210        NSS_CMSCipherContext_Destroy(encd->contentInfo.ciphcx);
00211        encd->contentInfo.ciphcx = NULL;
00212     }
00213 
00214     /* nothing to do after data */
00215     return SECSuccess;
00216 }
00217 
00218 
00219 /*
00220  * NSS_CMSEncryptedData_Decode_BeforeData - find bulk key & set up decryption
00221  */
00222 SECStatus
00223 NSS_CMSEncryptedData_Decode_BeforeData(NSSCMSEncryptedData *encd)
00224 {
00225     PK11SymKey *bulkkey = NULL;
00226     NSSCMSContentInfo *cinfo;
00227     SECAlgorithmID *bulkalg;
00228     SECStatus rv = SECFailure;
00229 
00230     cinfo = &(encd->contentInfo);
00231 
00232     bulkalg = NSS_CMSContentInfo_GetContentEncAlg(cinfo);
00233 
00234     if (encd->cmsg->decrypt_key_cb == NULL)      /* no callback? no key../ */
00235        goto loser;
00236 
00237     bulkkey = (*encd->cmsg->decrypt_key_cb)(encd->cmsg->decrypt_key_cb_arg, bulkalg);
00238     if (bulkkey == NULL)
00239        /* no success finding a bulk key */
00240        goto loser;
00241 
00242     NSS_CMSContentInfo_SetBulkKey(cinfo, bulkkey);
00243 
00244     cinfo->ciphcx = NSS_CMSCipherContext_StartDecrypt(bulkkey, bulkalg);
00245     if (cinfo->ciphcx == NULL)
00246        goto loser;          /* error has been set by NSS_CMSCipherContext_StartDecrypt */
00247 
00248 
00249     /* we are done with (this) bulkkey now. */
00250     PK11_FreeSymKey(bulkkey);
00251 
00252     rv = SECSuccess;
00253 
00254 loser:
00255     return rv;
00256 }
00257 
00258 /*
00259  * NSS_CMSEncryptedData_Decode_AfterData - finish decrypting this encryptedData's content
00260  */
00261 SECStatus
00262 NSS_CMSEncryptedData_Decode_AfterData(NSSCMSEncryptedData *encd)
00263 {
00264     if (encd->contentInfo.ciphcx) {
00265        NSS_CMSCipherContext_Destroy(encd->contentInfo.ciphcx);
00266        encd->contentInfo.ciphcx = NULL;
00267     }
00268 
00269     return SECSuccess;
00270 }
00271 
00272 /*
00273  * NSS_CMSEncryptedData_Decode_AfterEnd - finish decoding this encryptedData
00274  */
00275 SECStatus
00276 NSS_CMSEncryptedData_Decode_AfterEnd(NSSCMSEncryptedData *encd)
00277 {
00278     /* apply final touches */
00279     return SECSuccess;
00280 }