Back to index

lightning-sunbird  0.9+nobinonly
cmsutil.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  *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
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 /*
00039  * CMS miscellaneous utility functions.
00040  *
00041  * $Id: cmsutil.c,v 1.13.2.1 2006/01/21 19:01:34 rrelyea%redhat.com Exp $
00042  */
00043 
00044 #include "nssrenam.h"
00045 
00046 #include "cmslocal.h"
00047 
00048 #include "cert.h"
00049 #include "key.h"
00050 #include "secasn1.h"
00051 #include "secitem.h"
00052 #include "secoid.h"
00053 #include "pk11func.h"
00054 #include "secerr.h"
00055 #include "sechash.h"
00056 
00057 /*
00058  * NSS_CMSArray_SortByDER - sort array of objects by objects' DER encoding
00059  *
00060  * make sure that the order of the objects guarantees valid DER (which must be
00061  * in lexigraphically ascending order for a SET OF); if reordering is necessary it
00062  * will be done in place (in objs).
00063  */
00064 SECStatus
00065 NSS_CMSArray_SortByDER(void **objs, const SEC_ASN1Template *objtemplate, void **objs2)
00066 {
00067     PRArenaPool *poolp;
00068     int num_objs;
00069     SECItem **enc_objs;
00070     SECStatus rv = SECFailure;
00071     int i;
00072 
00073     if (objs == NULL)                                   /* already sorted */
00074        return SECSuccess;
00075 
00076     num_objs = NSS_CMSArray_Count((void **)objs);
00077     if (num_objs == 0 || num_objs == 1)          /* already sorted. */
00078        return SECSuccess;
00079 
00080     poolp = PORT_NewArena (1024);  /* arena for temporaries */
00081     if (poolp == NULL)
00082        return SECFailure;          /* no memory; nothing we can do... */
00083 
00084     /*
00085      * Allocate arrays to hold the individual encodings which we will use
00086      * for comparisons and the reordered attributes as they are sorted.
00087      */
00088     enc_objs = (SECItem **)PORT_ArenaZAlloc(poolp, (num_objs + 1) * sizeof(SECItem *));
00089     if (enc_objs == NULL)
00090        goto loser;
00091 
00092     /* DER encode each individual object. */
00093     for (i = 0; i < num_objs; i++) {
00094        enc_objs[i] = SEC_ASN1EncodeItem(poolp, NULL, objs[i], objtemplate);
00095        if (enc_objs[i] == NULL)
00096            goto loser;
00097     }
00098     enc_objs[num_objs] = NULL;
00099 
00100     /* now compare and sort objs by the order of enc_objs */
00101     NSS_CMSArray_Sort((void **)enc_objs, NSS_CMSUtil_DERCompare, objs, objs2);
00102 
00103     rv = SECSuccess;
00104 
00105 loser:
00106     PORT_FreeArena (poolp, PR_FALSE);
00107     return rv;
00108 }
00109 
00110 /*
00111  * NSS_CMSUtil_DERCompare - for use with NSS_CMSArray_Sort to
00112  *  sort arrays of SECItems containing DER
00113  */
00114 int
00115 NSS_CMSUtil_DERCompare(void *a, void *b)
00116 {
00117     SECItem *der1 = (SECItem *)a;
00118     SECItem *der2 = (SECItem *)b;
00119     unsigned int j;
00120 
00121     /*
00122      * Find the lowest (lexigraphically) encoding.  One that is
00123      * shorter than all the rest is known to be "less" because each
00124      * attribute is of the same type (a SEQUENCE) and so thus the
00125      * first octet of each is the same, and the second octet is
00126      * the length (or the length of the length with the high bit
00127      * set, followed by the length, which also works out to always
00128      * order the shorter first).  Two (or more) that have the
00129      * same length need to be compared byte by byte until a mismatch
00130      * is found.
00131      */
00132     if (der1->len != der2->len)
00133        return (der1->len < der2->len) ? -1 : 1;
00134 
00135     for (j = 0; j < der1->len; j++) {
00136        if (der1->data[j] == der2->data[j])
00137            continue;
00138        return (der1->data[j] < der2->data[j]) ? -1 : 1;
00139     }
00140     return 0;
00141 }
00142 
00143 /*
00144  * NSS_CMSAlgArray_GetIndexByAlgID - find a specific algorithm in an array of 
00145  * algorithms.
00146  *
00147  * algorithmArray - array of algorithm IDs
00148  * algid - algorithmid of algorithm to pick
00149  *
00150  * Returns:
00151  *  An integer containing the index of the algorithm in the array or -1 if 
00152  *  algorithm was not found.
00153  */
00154 int
00155 NSS_CMSAlgArray_GetIndexByAlgID(SECAlgorithmID **algorithmArray, SECAlgorithmID *algid)
00156 {
00157     int i;
00158 
00159     if (algorithmArray == NULL || algorithmArray[0] == NULL)
00160        return -1;
00161 
00162     for (i = 0; algorithmArray[i] != NULL; i++) {
00163        if (SECOID_CompareAlgorithmID(algorithmArray[i], algid) == SECEqual)
00164            break;    /* bingo */
00165     }
00166 
00167     if (algorithmArray[i] == NULL)
00168        return -1;    /* not found */
00169 
00170     return i;
00171 }
00172 
00173 /*
00174  * NSS_CMSAlgArray_GetIndexByAlgTag - find a specific algorithm in an array of 
00175  * algorithms.
00176  *
00177  * algorithmArray - array of algorithm IDs
00178  * algtag - algorithm tag of algorithm to pick
00179  *
00180  * Returns:
00181  *  An integer containing the index of the algorithm in the array or -1 if 
00182  *  algorithm was not found.
00183  */
00184 int
00185 NSS_CMSAlgArray_GetIndexByAlgTag(SECAlgorithmID **algorithmArray, 
00186                                  SECOidTag algtag)
00187 {
00188     SECOidData *algid;
00189     int i = -1;
00190 
00191     if (algorithmArray == NULL || algorithmArray[0] == NULL)
00192        return i;
00193 
00194 #ifdef ORDER_N_SQUARED
00195     for (i = 0; algorithmArray[i] != NULL; i++) {
00196        algid = SECOID_FindOID(&(algorithmArray[i]->algorithm));
00197        if (algid->offset == algtag)
00198            break;    /* bingo */
00199     }
00200 #else
00201     algid = SECOID_FindOIDByTag(algtag);
00202     if (!algid) 
00203        return i;
00204     for (i = 0; algorithmArray[i] != NULL; i++) {
00205        if (SECITEM_ItemsAreEqual(&algorithmArray[i]->algorithm, &algid->oid))
00206            break;    /* bingo */
00207     }
00208 #endif
00209 
00210     if (algorithmArray[i] == NULL)
00211        return -1;    /* not found */
00212 
00213     return i;
00214 }
00215 
00216 const SECHashObject *
00217 NSS_CMSUtil_GetHashObjByAlgID(SECAlgorithmID *algid)
00218 {
00219     SECOidTag oidTag = SECOID_FindOIDTag(&(algid->algorithm));
00220     const SECHashObject *digobj = HASH_GetHashObjectByOidTag(oidTag);
00221 
00222     return digobj;
00223 }
00224 
00225 /*
00226  * XXX I would *really* like to not have to do this, but the current
00227  * signing interface gives me little choice.
00228  */
00229 SECOidTag
00230 NSS_CMSUtil_MakeSignatureAlgorithm(SECOidTag hashalg, SECOidTag encalg)
00231 {
00232     switch (encalg) {
00233       case SEC_OID_PKCS1_RSA_ENCRYPTION:
00234        switch (hashalg) {
00235          case SEC_OID_MD2:
00236            return SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION;
00237          case SEC_OID_MD5:
00238            return SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION;
00239          case SEC_OID_SHA1:
00240            return SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
00241          case SEC_OID_SHA256:
00242            return SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION;
00243          case SEC_OID_SHA384:
00244            return SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION;
00245          case SEC_OID_SHA512:
00246            return SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION;
00247          default:
00248            return SEC_OID_UNKNOWN;
00249        }
00250       case SEC_OID_ANSIX9_DSA_SIGNATURE:
00251       case SEC_OID_MISSI_KEA_DSS:
00252       case SEC_OID_MISSI_DSS:
00253        switch (hashalg) {
00254          case SEC_OID_SHA1:
00255            return SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST;
00256          default:
00257            return SEC_OID_UNKNOWN;
00258        }
00259       case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
00260        switch (hashalg) {
00261          case SEC_OID_SHA1:
00262            return SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE;
00263          case SEC_OID_SHA256:
00264            return SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE;
00265          case SEC_OID_SHA384:
00266            return SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE;
00267          case SEC_OID_SHA512:
00268            return SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE;
00269          default:
00270            return SEC_OID_UNKNOWN;
00271        }
00272       default:
00273        break;
00274     }
00275 
00276     return encalg;          /* maybe it is already the right algid */
00277 }
00278 
00279 const SEC_ASN1Template *
00280 NSS_CMSUtil_GetTemplateByTypeTag(SECOidTag type)
00281 {
00282     const SEC_ASN1Template *template;
00283     extern const SEC_ASN1Template NSSCMSSignedDataTemplate[];
00284     extern const SEC_ASN1Template NSSCMSEnvelopedDataTemplate[];
00285     extern const SEC_ASN1Template NSSCMSEncryptedDataTemplate[];
00286     extern const SEC_ASN1Template NSSCMSDigestedDataTemplate[];
00287 
00288     switch (type) {
00289     case SEC_OID_PKCS7_SIGNED_DATA:
00290        template = NSSCMSSignedDataTemplate;
00291        break;
00292     case SEC_OID_PKCS7_ENVELOPED_DATA:
00293        template = NSSCMSEnvelopedDataTemplate;
00294        break;
00295     case SEC_OID_PKCS7_ENCRYPTED_DATA:
00296        template = NSSCMSEncryptedDataTemplate;
00297        break;
00298     case SEC_OID_PKCS7_DIGESTED_DATA:
00299        template = NSSCMSDigestedDataTemplate;
00300        break;
00301     default:
00302     case SEC_OID_PKCS7_DATA:
00303        template = NULL;
00304        break;
00305     }
00306     return template;
00307 }
00308 
00309 size_t
00310 NSS_CMSUtil_GetSizeByTypeTag(SECOidTag type)
00311 {
00312     size_t size;
00313 
00314     switch (type) {
00315     case SEC_OID_PKCS7_SIGNED_DATA:
00316        size = sizeof(NSSCMSSignedData);
00317        break;
00318     case SEC_OID_PKCS7_ENVELOPED_DATA:
00319        size = sizeof(NSSCMSEnvelopedData);
00320        break;
00321     case SEC_OID_PKCS7_ENCRYPTED_DATA:
00322        size = sizeof(NSSCMSEncryptedData);
00323        break;
00324     case SEC_OID_PKCS7_DIGESTED_DATA:
00325        size = sizeof(NSSCMSDigestedData);
00326        break;
00327     default:
00328     case SEC_OID_PKCS7_DATA:
00329        size = 0;
00330        break;
00331     }
00332     return size;
00333 }
00334 
00335 NSSCMSContentInfo *
00336 NSS_CMSContent_GetContentInfo(void *msg, SECOidTag type)
00337 {
00338     NSSCMSContent c;
00339     NSSCMSContentInfo *cinfo = NULL;
00340 
00341     if (!msg)
00342        return cinfo;
00343     c.pointer = msg;
00344     switch (type) {
00345     case SEC_OID_PKCS7_SIGNED_DATA:
00346        cinfo = &(c.signedData->contentInfo);
00347        break;
00348     case SEC_OID_PKCS7_ENVELOPED_DATA:
00349        cinfo = &(c.envelopedData->contentInfo);
00350        break;
00351     case SEC_OID_PKCS7_ENCRYPTED_DATA:
00352        cinfo = &(c.encryptedData->contentInfo);
00353        break;
00354     case SEC_OID_PKCS7_DIGESTED_DATA:
00355        cinfo = &(c.digestedData->contentInfo);
00356        break;
00357     default:
00358        cinfo = NULL;
00359     }
00360     return cinfo;
00361 }
00362 
00363 const char *
00364 NSS_CMSUtil_VerificationStatusToString(NSSCMSVerificationStatus vs)
00365 {
00366     switch (vs) {
00367     case NSSCMSVS_Unverified:                    return "Unverified";
00368     case NSSCMSVS_GoodSignature:          return "GoodSignature";
00369     case NSSCMSVS_BadSignature:                  return "BadSignature";
00370     case NSSCMSVS_DigestMismatch:         return "DigestMismatch";
00371     case NSSCMSVS_SigningCertNotFound:           return "SigningCertNotFound";
00372     case NSSCMSVS_SigningCertNotTrusted:  return "SigningCertNotTrusted";
00373     case NSSCMSVS_SignatureAlgorithmUnknown:     return "SignatureAlgorithmUnknown";
00374     case NSSCMSVS_SignatureAlgorithmUnsupported: return "SignatureAlgorithmUnsupported";
00375     case NSSCMSVS_MalformedSignature:            return "MalformedSignature";
00376     case NSSCMSVS_ProcessingError:        return "ProcessingError";
00377     default:                              return "Unknown";
00378     }
00379 }
00380 
00381 SECStatus
00382 NSS_CMSDEREncode(NSSCMSMessage *cmsg, SECItem *input, SECItem *derOut, 
00383                  PLArenaPool *arena)
00384 {
00385     NSSCMSEncoderContext *ecx;
00386     SECStatus rv = SECSuccess;
00387     if (!cmsg || !derOut || !arena) {
00388        PORT_SetError(SEC_ERROR_INVALID_ARGS);
00389        return SECFailure;
00390     }
00391     ecx = NSS_CMSEncoder_Start(cmsg, 0, 0, derOut, arena, 0, 0, 0, 0, 0, 0);
00392     if (!ecx) {
00393        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
00394        return SECFailure;
00395     }
00396     if (input) {
00397        rv = NSS_CMSEncoder_Update(ecx, (const char*)input->data, input->len);
00398        if (rv) {
00399            PORT_SetError(SEC_ERROR_BAD_DATA);
00400        }
00401     }
00402     rv |= NSS_CMSEncoder_Finish(ecx);
00403     if (rv) {
00404        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
00405     }
00406     return rv;
00407 }