Back to index

lightning-sunbird  0.9+nobinonly
cobject.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  * Portions created by Red Hat, Inc, are Copyright (C) 2005
00021  *
00022  * Contributor(s):
00023  *   Bob Relyea (rrelyea@redhat.com)
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 #ifdef DEBUG
00039 static const char CVS_ID[] = "@(#) $RCSfile: cobject.c,v $ $Revision: 1.4 $ $Date: 2005/11/16 01:17:25 $";
00040 #endif /* DEBUG */
00041 
00042 #include "ckcapi.h"
00043 #include "nssbase.h"
00044 
00045 /*
00046  * ckcapi/cobject.c
00047  *
00048  * This file implements the NSSCKMDObject object for the
00049  * "nss to capi objects" cryptoki module.
00050  */
00051 
00052 const CK_ATTRIBUTE_TYPE certAttrs[] = {
00053     CKA_CLASS,
00054     CKA_TOKEN,
00055     CKA_PRIVATE,
00056     CKA_MODIFIABLE,
00057     CKA_LABEL,
00058     CKA_CERTIFICATE_TYPE,
00059     CKA_SUBJECT,
00060     CKA_ISSUER,
00061     CKA_SERIAL_NUMBER,
00062     CKA_VALUE
00063 };
00064 const PRUint32 certAttrsCount = NSS_CKCAPI_ARRAY_SIZE(certAttrs);
00065 
00066 /* private keys, for now only support RSA */
00067 const CK_ATTRIBUTE_TYPE privKeyAttrs[] = {
00068     CKA_CLASS,
00069     CKA_TOKEN,
00070     CKA_PRIVATE,
00071     CKA_MODIFIABLE,
00072     CKA_LABEL,
00073     CKA_KEY_TYPE,
00074     CKA_DERIVE,
00075     CKA_LOCAL,
00076     CKA_SUBJECT,
00077     CKA_SENSITIVE,
00078     CKA_DECRYPT,
00079     CKA_SIGN,
00080     CKA_SIGN_RECOVER,
00081     CKA_UNWRAP,
00082     CKA_EXTRACTABLE,
00083     CKA_ALWAYS_SENSITIVE,
00084     CKA_NEVER_EXTRACTABLE,
00085     CKA_MODULUS,
00086     CKA_PUBLIC_EXPONENT,
00087 };
00088 const PRUint32 privKeyAttrsCount = NSS_CKCAPI_ARRAY_SIZE(privKeyAttrs);
00089 
00090 /* public keys, for now only support RSA */
00091 const CK_ATTRIBUTE_TYPE pubKeyAttrs[] = {
00092     CKA_CLASS,
00093     CKA_TOKEN,
00094     CKA_PRIVATE,
00095     CKA_MODIFIABLE,
00096     CKA_LABEL,
00097     CKA_KEY_TYPE,
00098     CKA_DERIVE,
00099     CKA_LOCAL,
00100     CKA_SUBJECT,
00101     CKA_ENCRYPT,
00102     CKA_VERIFY,
00103     CKA_VERIFY_RECOVER,
00104     CKA_WRAP,
00105     CKA_MODULUS,
00106     CKA_PUBLIC_EXPONENT,
00107 };
00108 const PRUint32 pubKeyAttrsCount = NSS_CKCAPI_ARRAY_SIZE(pubKeyAttrs);
00109 static const CK_BBOOL ck_true = CK_TRUE;
00110 static const CK_BBOOL ck_false = CK_FALSE;
00111 static const CK_CERTIFICATE_TYPE ckc_x509 = CKC_X_509;
00112 static const CK_KEY_TYPE ckk_rsa = CKK_RSA;
00113 static const CK_OBJECT_CLASS cko_certificate = CKO_CERTIFICATE;
00114 static const CK_OBJECT_CLASS cko_private_key = CKO_PRIVATE_KEY;
00115 static const CK_OBJECT_CLASS cko_public_key = CKO_PUBLIC_KEY;
00116 static const NSSItem ckcapi_trueItem = { 
00117   (void *)&ck_true, (PRUint32)sizeof(CK_BBOOL) };
00118 static const NSSItem ckcapi_falseItem = { 
00119   (void *)&ck_false, (PRUint32)sizeof(CK_BBOOL) };
00120 static const NSSItem ckcapi_x509Item = { 
00121   (void *)&ckc_x509, (PRUint32)sizeof(CKC_X_509) };
00122 static const NSSItem ckcapi_rsaItem = { 
00123   (void *)&ckk_rsa, (PRUint32)sizeof(CK_KEY_TYPE) };
00124 static const NSSItem ckcapi_certClassItem = { 
00125   (void *)&cko_certificate, (PRUint32)sizeof(CK_OBJECT_CLASS) };
00126 static const NSSItem ckcapi_privKeyClassItem = {
00127   (void *)&cko_private_key, (PRUint32)sizeof(CK_OBJECT_CLASS) };
00128 static const NSSItem ckcapi_pubKeyClassItem = {
00129   (void *)&cko_public_key, (PRUint32)sizeof(CK_OBJECT_CLASS) };
00130 static const NSSItem ckcapi_emptyItem = { 
00131   (void *)&ck_true, 0};
00132 
00133 /*
00134  * these are utilities. The chould be moved to a new utilities file.
00135  */
00136 
00137 /*
00138  * unwrap a single DER value
00139  */
00140 char *
00141 nss_ckcapi_DERUnwrap
00142 (
00143   char *src, 
00144   int size, 
00145   int *outSize, 
00146   char **next
00147 )
00148 {
00149   unsigned char *start = src;
00150   unsigned char *end = src+size;
00151   unsigned int len = 0;
00152 
00153   /* initialize error condition return values */
00154   *outSize = 0;
00155   if (next) {
00156     *next = src;
00157   }
00158 
00159   if (size < 2) {
00160     return start;
00161   }
00162   src ++ ; /* skip the tag -- should check it against an expected value! */
00163   len = (unsigned) *src++;
00164   if (len & 0x80) {
00165     int count = len & 0x7f;
00166     len =0;
00167 
00168     if (count+2 > size) {
00169       return start;
00170     }
00171     while (count-- > 0) {
00172       len = (len << 8) | (unsigned) *src++;
00173     }
00174   }
00175   if (len + (src-start) > (unsigned int)size) {
00176     return start;
00177   }
00178   if (next) {
00179     *next = src+len;
00180   }
00181   *outSize = len;
00182 
00183   return src;
00184 }
00185 
00186 /*
00187  * convert a PKCS #11 bytestrin into a CK_ULONG, the byte stream must be
00188  * less than sizeof (CK_ULONG).
00189  */
00190 CK_ULONG  
00191 nss_ckcapi_DataToInt
00192 (
00193   NSSItem *data,
00194   CK_RV *pError
00195 )
00196 {
00197   CK_ULONG value = 0;
00198   unsigned long count = data->size;
00199   unsigned char *dataPtr = data->data;
00200   unsigned long size = 0;
00201 
00202   *pError = CKR_OK;
00203 
00204   while (count--) {
00205     value = value << 8;
00206     value = value + *dataPtr++;
00207     if (size || value) {
00208       size++;
00209     }
00210   }
00211   if (size > sizeof(CK_ULONG)) {
00212     *pError = CKR_ATTRIBUTE_VALUE_INVALID;
00213   }
00214   return value;
00215 }
00216 
00217 /*
00218  * convert a CK_ULONG to a bytestream. Data is stored in the buffer 'buf'
00219  * and must be at least CK_ULONG. Caller must provide buf.
00220  */
00221 CK_ULONG  
00222 nss_ckcapi_IntToData
00223 (
00224   CK_ULONG value,
00225   NSSItem *data,
00226   unsigned char *dataPtr,
00227   CK_RV *pError
00228 )
00229 {
00230   unsigned long count = 0;
00231   unsigned long i;
00232 #define SHIFT ((sizeof(CK_ULONG)-1)*8)
00233   PRBool first = 0;
00234 
00235   *pError = CKR_OK;
00236 
00237   data->data = dataPtr;
00238   for (i=0; i < sizeof(CK_ULONG); i++) {
00239     unsigned char digit = (unsigned char)((value >> SHIFT) & 0xff);
00240 
00241     value = value << 8;
00242 
00243     /* drop leading zero bytes */
00244     if (first && (0 == digit)) {
00245        continue;
00246     }
00247     *dataPtr++ = digit;
00248     count++;
00249   }
00250   data->size = count;
00251   return count;
00252 }
00253 
00254 /*
00255  * get an attribute from a template. Value is returned in NSS item.
00256  * data for the item is owned by the template.
00257  */
00258 CK_RV
00259 nss_ckcapi_GetAttribute
00260 (
00261   CK_ATTRIBUTE_TYPE type,
00262   CK_ATTRIBUTE *template,
00263   CK_ULONG templateSize, 
00264   NSSItem *item
00265 )
00266 {
00267   CK_ULONG i;
00268 
00269   for (i=0; i < templateSize; i++) {
00270     if (template[i].type == type) {
00271       item->data = template[i].pValue;
00272       item->size = template[i].ulValueLen;
00273       return CKR_OK;
00274     }
00275   }
00276   return CKR_TEMPLATE_INCOMPLETE;
00277 }
00278 
00279 /*
00280  * get an attribute which is type CK_ULONG.
00281  */
00282 CK_ULONG
00283 nss_ckcapi_GetULongAttribute
00284 (
00285   CK_ATTRIBUTE_TYPE type,
00286   CK_ATTRIBUTE *template,
00287   CK_ULONG templateSize, 
00288   CK_RV *pError
00289 )
00290 {
00291   NSSItem item;
00292 
00293   *pError = nss_ckcapi_GetAttribute(type, template, templateSize, &item);
00294   if (CKR_OK != *pError) {
00295     return (CK_ULONG) 0;
00296   }
00297   if (item.size != sizeof(CK_ULONG)) {
00298     *pError = CKR_ATTRIBUTE_VALUE_INVALID;
00299     return (CK_ULONG) 0;
00300   }
00301   return *(CK_ULONG *)item.data;
00302 }
00303 
00304 /*
00305  * get an attribute which is type CK_BBOOL.
00306  */
00307 CK_BBOOL
00308 nss_ckcapi_GetBoolAttribute
00309 (
00310   CK_ATTRIBUTE_TYPE type,
00311   CK_ATTRIBUTE *template,
00312   CK_ULONG templateSize, 
00313   CK_RV *pError
00314 )
00315 {
00316   NSSItem item;
00317 
00318   *pError = nss_ckcapi_GetAttribute(type, template, templateSize, &item);
00319   if (CKR_OK != *pError) {
00320     return (CK_BBOOL) 0;
00321   }
00322   if (item.size != sizeof(CK_BBOOL)) {
00323     *pError = CKR_ATTRIBUTE_VALUE_INVALID;
00324     return (CK_BBOOL) 0;
00325   }
00326   return *(CK_BBOOL *)item.data;
00327 }
00328 
00329 /*
00330  * get an attribute which is type CK_BBOOL.
00331  */
00332 char *
00333 nss_ckcapi_GetStringAttribute
00334 (
00335   CK_ATTRIBUTE_TYPE type,
00336   CK_ATTRIBUTE *template,
00337   CK_ULONG templateSize, 
00338   CK_RV *pError
00339 )
00340 {
00341   NSSItem item;
00342   char *str;
00343 
00344   /* get the attribute */
00345   *pError = nss_ckcapi_GetAttribute(type, template, templateSize, &item);
00346   if (CKR_OK != *pError) {
00347     return (char *)NULL;
00348   }
00349   /* make sure it is null terminated */
00350   str = nss_ZNEWARRAY(NULL, char, item.size+1);
00351   if ((char *)NULL == str) {
00352     *pError = CKR_HOST_MEMORY;
00353     return (char *)NULL;
00354   }
00355 
00356   nsslibc_memcpy(str, item.data, item.size);
00357   str[item.size] = 0;
00358 
00359   return str;
00360 }
00361 
00362 /*
00363  * Return the size in bytes of a wide string
00364  */
00365 int
00366 nss_ckcapi_WideSize
00367 (
00368   LPCWSTR wide
00369 )
00370 {
00371   DWORD size;
00372 
00373   if ((LPWSTR)NULL == wide) {
00374     return 0;
00375   }
00376   size = wcslen(wide)+1;
00377   return size*2;
00378 }
00379 
00380 /*
00381  * Covert a Unicode wide character string to a UTF8 string
00382  */
00383 char *
00384 nss_ckcapi_WideToUTF8
00385 (
00386   LPCWSTR wide 
00387 )
00388 {
00389   DWORD len;
00390   DWORD size;
00391   char *buf;
00392 
00393   if ((LPWSTR)NULL == wide) {
00394     return (char *)NULL;
00395   }
00396 
00397   len = nss_ckcapi_WideSize(wide);
00398 
00399   size = WideCharToMultiByte(CP_UTF8, 0, wide, len, NULL, 0, NULL, 0);
00400   if (size == 0) {
00401     return (char *)NULL;
00402   }
00403   buf = nss_ZNEWARRAY(NULL, char, size);
00404   size = WideCharToMultiByte(CP_UTF8, 0, wide, len, buf, size, NULL, 0);
00405   if (size == 0) {
00406     nss_ZFreeIf(buf);
00407     return (char *)NULL;
00408   }
00409   return buf;
00410 }
00411 
00412 /*
00413  * Return a Wide String duplicated with nss allocated memory.
00414  */
00415 LPWSTR
00416 nss_ckcapi_WideDup
00417 (
00418   LPCWSTR wide
00419 )
00420 {
00421   DWORD len = nss_ckcapi_WideSize(wide);
00422   LPWSTR buf;
00423 
00424   if ((LPWSTR)NULL == wide) {
00425     return (LPWSTR)NULL;
00426   }
00427 
00428   len = nss_ckcapi_WideSize(wide);
00429 
00430   buf = (LPWSTR) nss_ZNEWARRAY(NULL, char, len);
00431   if ((LPWSTR) NULL == buf) {
00432     return buf;
00433   }
00434   nsslibc_memcpy(buf, wide, len);
00435   return buf;
00436 }
00437 
00438 /*
00439  * Covert a UTF8 string to Unicode wide character
00440  */
00441 LPWSTR
00442 nss_ckcapi_UTF8ToWide
00443 (
00444   char *buf
00445 )
00446 {
00447   DWORD size;
00448   DWORD len = strlen(buf)+1;
00449   LPWSTR wide;
00450 
00451   if ((char *)NULL == buf) {
00452     return (LPWSTR) NULL;
00453   }
00454     
00455   len = strlen(buf)+1;
00456 
00457   size = MultiByteToWideChar(CP_UTF8, 0, buf, len, NULL, 0);
00458   if (size == 0) {
00459     return (LPWSTR) NULL;
00460   }
00461   wide = nss_ZNEWARRAY(NULL, WCHAR, size);
00462   size = MultiByteToWideChar(CP_UTF8, 0, buf, len, wide, size);
00463   if (size == 0) {
00464     nss_ZFreeIf(wide);
00465     return (LPWSTR) NULL;
00466   }
00467   return wide;
00468 }
00469 
00470 
00471 /*
00472  * keep all the knowlege of how the internalObject is laid out in this function
00473  *
00474  * nss_ckcapi_FetchKeyContainer
00475  *
00476  * fetches the Provider container and info as well as a key handle for a
00477  * private key. If something other than a private key is passed in,
00478  * this function fails with CKR_KEY_TYPE_INCONSISTENT
00479  */
00480 NSS_EXTERN CK_RV
00481 nss_ckcapi_FetchKeyContainer
00482 (
00483   ckcapiInternalObject *iKey,
00484   HCRYPTPROV *hProv, 
00485   DWORD *keySpec,
00486   HCRYPTKEY *hKey
00487 )
00488 {
00489   ckcapiCertObject *co;
00490   ckcapiKeyObject *ko;
00491   BOOL rc, dummy;
00492   DWORD msError;
00493 
00494 
00495   switch (iKey->type) {
00496   default:
00497   case ckcapiRaw:
00498      /* can't have raw private keys */
00499      return CKR_KEY_TYPE_INCONSISTENT;
00500   case ckcapiCert:
00501     if (iKey->objClass != CKO_PRIVATE_KEY) {
00502       /* Only private keys have private key provider handles */
00503       return CKR_KEY_TYPE_INCONSISTENT;
00504     }
00505     co = &iKey->u.cert;
00506 
00507     /* OK, get the Provider */
00508     rc = CryptAcquireCertificatePrivateKey(co->certContext,
00509       CRYPT_ACQUIRE_CACHE_FLAG|CRYPT_ACQUIRE_COMPARE_KEY_FLAG, NULL, hProv, 
00510       keySpec, &dummy);
00511     if (!rc) {
00512       goto loser;
00513     }
00514     break;
00515   case ckcapiBareKey:
00516     if (iKey->objClass != CKO_PRIVATE_KEY) {
00517        /* Only private keys have private key provider handles */
00518        return CKR_KEY_TYPE_INCONSISTENT;
00519     }
00520     ko = &iKey->u.key;
00521 
00522     /* OK, get the Provider */
00523     if (0 == ko->hProv) {
00524       rc = CryptAcquireContext(hProv,
00525                             ko->containerName, 
00526                             ko->provName,
00527                                ko->provInfo.dwProvType , 0);
00528       if (!rc) {
00529         goto loser;
00530       }
00531     } else {
00532       *hProv = ko->hProv;
00533     }
00534     *keySpec = ko->provInfo.dwKeySpec;
00535     break;
00536   }
00537 
00538   /* and get the crypto handle */
00539   rc = CryptGetUserKey(*hProv, *keySpec, hKey);
00540   if (!rc) {
00541     goto loser;
00542   }
00543   return CKR_OK;
00544 loser:
00545   /* map the microsoft error before leaving */
00546   msError = GetLastError();
00547   switch (msError) {
00548   case ERROR_INVALID_HANDLE:
00549   case ERROR_INVALID_PARAMETER:
00550   case NTE_BAD_KEY:
00551   case NTE_NO_KEY:
00552   case NTE_BAD_PUBLIC_KEY:
00553   case NTE_BAD_KEYSET:
00554   case NTE_KEYSET_NOT_DEF:
00555     return CKR_KEY_TYPE_INCONSISTENT;
00556   case NTE_BAD_UID:
00557   case NTE_KEYSET_ENTRY_BAD:
00558     return CKR_DEVICE_ERROR;
00559   }
00560   return CKR_GENERAL_ERROR;
00561 }
00562 
00563 
00564 /*
00565  * take a DER PUBLIC Key block and return the modulus and exponent
00566  */
00567 static void
00568 ckcapi_CertPopulateModulusExponent
00569 (
00570   ckcapiInternalObject *io
00571 )
00572 {
00573   ckcapiKeyParams *kp = &io->u.cert.key;
00574   PCCERT_CONTEXT certContext = io->u.cert.certContext;
00575   char *pkData = certContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData;
00576   CK_ULONG size= certContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData;
00577   CK_ULONG newSize;
00578   char *ptr, *newptr;
00579 
00580   /* find the start of the modulus -- this will not give good results if
00581    * the key isn't an rsa key! */
00582   ptr = nss_ckcapi_DERUnwrap(pkData, size, &newSize, NULL);
00583   kp->modulus.data = nss_ckcapi_DERUnwrap(ptr, newSize, 
00584                                            &kp->modulus.size, &newptr);
00585   /* changed from signed to unsigned int */
00586   if (0 == *(char *)kp->modulus.data) {
00587     kp->modulus.data = ((char *)kp->modulus.data)+1;
00588     kp->modulus.size = kp->modulus.size - 1;
00589   }
00590   /* changed from signed to unsigned int */
00591   kp->exponent.data = nss_ckcapi_DERUnwrap(newptr, (newptr-ptr)+newSize, 
00592                                           &kp->exponent.size, NULL);
00593   if (0 == *(char *)kp->exponent.data) {
00594     kp->exponent.data = ((char *)kp->exponent.data)+1;
00595     kp->exponent.size = kp->exponent.size - 1;
00596   }
00597   return;
00598 }
00599 
00600 typedef struct _CAPI_RSA_KEY_BLOB {
00601   PUBLICKEYSTRUC header;
00602   RSAPUBKEY  rsa;
00603   char      data[1];
00604 } CAPI_RSA_KEY_BLOB;
00605 
00606 #define CAPI_MODULUS_OFFSET(modSize)     0
00607 #define CAPI_PRIME_1_OFFSET(modSize)     (modSize)
00608 #define CAPI_PRIME_2_OFFSET(modSize)     ((modSize)+(modSize)/2)
00609 #define CAPI_EXPONENT_1_OFFSET(modSize)  ((modSize)*2)
00610 #define CAPI_EXPONENT_2_OFFSET(modSize)  ((modSize)*2+(modSize)/2)
00611 #define CAPI_COEFFICIENT_OFFSET(modSize) ((modSize)*3)
00612 #define CAPI_PRIVATE_EXP_OFFSET(modSize) ((modSize)*3+(modSize)/2)
00613 
00614 void
00615 ckcapi_FetchPublicKey
00616 (
00617   ckcapiInternalObject *io
00618 )
00619 {
00620   ckcapiKeyParams *kp;
00621   HCRYPTPROV hProv;
00622   DWORD keySpec;
00623   HCRYPTKEY hKey = 0;
00624   CK_RV error;
00625   DWORD bufLen;
00626   BOOL rc;
00627   unsigned long modulus;
00628   char *buf = NULL;
00629   CAPI_RSA_KEY_BLOB *blob;
00630 
00631   error = nss_ckcapi_FetchKeyContainer(io, &hProv, &keySpec, &hKey);
00632   if (CKR_OK != error) {
00633     goto loser;
00634   }
00635   kp = (ckcapiCert == io->type) ?  &io->u.cert.key : &io->u.key.key;
00636 
00637   rc = CryptExportKey(hKey, 0, PUBLICKEYBLOB, 0, buf, &bufLen);
00638   if (!rc) {
00639     goto loser;
00640   }
00641   buf = nss_ZNEWARRAY(NULL, char, bufLen);
00642   rc = CryptExportKey(hKey, 0, PUBLICKEYBLOB, 0, buf, &bufLen);
00643   if (!rc) {
00644     goto loser;
00645   }
00646   /* validate the blob */
00647   blob = (CAPI_RSA_KEY_BLOB *)buf;
00648   if ((PUBLICKEYBLOB != blob->header.bType) ||
00649       (0x02 != blob->header.bVersion) ||
00650       (0x31415352 != blob->rsa.magic)) {
00651     goto loser;
00652   }
00653   modulus = blob->rsa.bitlen/8;
00654   kp->pubKey = buf;
00655   buf = NULL;
00656 
00657   kp->modulus.data = &blob->data[CAPI_MODULUS_OFFSET(modulus)];
00658   kp->modulus.size = modulus;
00659   ckcapi_ReverseData(&kp->modulus);
00660   nss_ckcapi_IntToData(blob->rsa.pubexp, &kp->exponent,
00661                      kp->publicExponentData, &error);
00662 
00663 loser:
00664   nss_ZFreeIf(buf);
00665   if (0 != hKey) {
00666      CryptDestroyKey(hKey);
00667   }
00668   return;
00669 }
00670 
00671 void
00672 ckcapi_FetchPrivateKey
00673 (
00674   ckcapiInternalObject *io
00675 )
00676 {
00677   ckcapiKeyParams *kp;
00678   HCRYPTPROV hProv;
00679   DWORD keySpec;
00680   HCRYPTKEY hKey = 0;
00681   CK_RV error;
00682   DWORD bufLen;
00683   BOOL rc;
00684   unsigned long modulus;
00685   char *buf = NULL;
00686   CAPI_RSA_KEY_BLOB *blob;
00687 
00688   error = nss_ckcapi_FetchKeyContainer(io, &hProv, &keySpec, &hKey);
00689   if (CKR_OK != error) {
00690     goto loser;
00691   }
00692   kp = (ckcapiCert == io->type) ?  &io->u.cert.key : &io->u.key.key;
00693 
00694   rc = CryptExportKey(hKey, 0, PRIVATEKEYBLOB, 0, buf, &bufLen);
00695   if (!rc) {
00696     goto loser;
00697   }
00698   buf = nss_ZNEWARRAY(NULL, char, bufLen);
00699   rc = CryptExportKey(hKey, 0, PRIVATEKEYBLOB, 0, buf, &bufLen);
00700   if (!rc) {
00701     goto loser;
00702   }
00703   /* validate the blob */
00704   blob = (CAPI_RSA_KEY_BLOB *)buf;
00705   if ((PRIVATEKEYBLOB != blob->header.bType) ||
00706       (0x02 != blob->header.bVersion) ||
00707       (0x32415352 != blob->rsa.magic)) {
00708     goto loser;
00709   }
00710   modulus = blob->rsa.bitlen/8;
00711   kp->privateKey = buf;
00712   buf = NULL;
00713 
00714   kp->privateExponent.data = &blob->data[CAPI_PRIVATE_EXP_OFFSET(modulus)];
00715   kp->privateExponent.size = modulus;
00716   ckcapi_ReverseData(&kp->privateExponent);
00717   kp->prime1.data = &blob->data[CAPI_PRIME_1_OFFSET(modulus)];
00718   kp->prime1.size = modulus/2;
00719   ckcapi_ReverseData(&kp->prime1);
00720   kp->prime2.data = &blob->data[CAPI_PRIME_2_OFFSET(modulus)];
00721   kp->prime2.size = modulus/2;
00722   ckcapi_ReverseData(&kp->prime2);
00723   kp->exponent1.data = &blob->data[CAPI_EXPONENT_1_OFFSET(modulus)];
00724   kp->exponent1.size = modulus/2;
00725   ckcapi_ReverseData(&kp->exponent1);
00726   kp->exponent2.data = &blob->data[CAPI_EXPONENT_2_OFFSET(modulus)];
00727   kp->exponent2.size = modulus/2;
00728   ckcapi_ReverseData(&kp->exponent2);
00729   kp->coefficient.data = &blob->data[CAPI_COEFFICIENT_OFFSET(modulus)];
00730   kp->coefficient.size = modulus/2;
00731   ckcapi_ReverseData(&kp->coefficient);
00732 
00733 loser:
00734   nss_ZFreeIf(buf);
00735   if (0 != hKey) {
00736      CryptDestroyKey(hKey);
00737   }
00738   return;
00739 }
00740 
00741 
00742 void
00743 ckcapi_PopulateModulusExponent
00744 (
00745   ckcapiInternalObject *io
00746 )
00747 {
00748   if (ckcapiCert == io->type) {
00749     ckcapi_CertPopulateModulusExponent(io);
00750   } else {
00751     ckcapi_FetchPublicKey(io);
00752   } 
00753   return;
00754 }
00755 
00756 /*
00757  * fetch the friendly name attribute.
00758  * can only be called with ckcapiCert type objects!
00759  */
00760 void
00761 ckcapi_FetchLabel
00762 (
00763   ckcapiInternalObject *io
00764 )
00765 {
00766   ckcapiCertObject *co = &io->u.cert;
00767   char *label;
00768   PCCERT_CONTEXT certContext = io->u.cert.certContext;
00769   char labelDataUTF16[128];
00770   DWORD size = sizeof(labelDataUTF16);
00771   DWORD size8 = sizeof(co->labelData);
00772   BOOL rv;
00773 
00774   rv = CertGetCertificateContextProperty(certContext,
00775        CERT_FRIENDLY_NAME_PROP_ID, labelDataUTF16, &size);
00776   if (rv) {
00777     co->labelData = nss_ckcapi_WideToUTF8((LPCWSTR)labelDataUTF16);
00778     if ((CHAR *)NULL == co->labelData) {
00779       rv = 0;
00780     } else {
00781       size = strlen(co->labelData);
00782     }
00783   }
00784   label = co->labelData;
00785   /* we are presuming a user cert, make sure it has a nickname, even if
00786    * Microsoft never gave it one */
00787   if (!rv && co->hasID) {
00788     DWORD mserror = GetLastError();
00789 #define DEFAULT_NICKNAME "no Microsoft nickname"
00790     label = DEFAULT_NICKNAME;
00791     size = sizeof(DEFAULT_NICKNAME);
00792     rv = 1;
00793   }
00794     
00795   if (rv) {
00796     co->label.data = label;
00797     co->label.size = size;
00798   }
00799   return;
00800 }
00801 
00802 void
00803 ckcapi_FetchSerial
00804 (
00805   ckcapiInternalObject *io
00806 )
00807 {
00808   ckcapiCertObject *co = &io->u.cert;
00809   PCCERT_CONTEXT certContext = io->u.cert.certContext;
00810   DWORD size = sizeof(co->derSerial);
00811 
00812   BOOL rc = CryptEncodeObject(X509_ASN_ENCODING,
00813                          X509_MULTI_BYTE_INTEGER,
00814                          &certContext->pCertInfo->SerialNumber,
00815                       co->derSerial,
00816                          &size);
00817   if (rc) {
00818     co->serial.data = co->derSerial;
00819     co->serial.size = size;
00820   }
00821   return;
00822 }
00823 
00824 /*
00825  * fetch the key ID.
00826  */
00827 void
00828 ckcapi_FetchID
00829 (
00830   ckcapiInternalObject *io
00831 )
00832 {
00833   PCCERT_CONTEXT certContext = io->u.cert.certContext;
00834   DWORD size = 0;
00835   BOOL rc;
00836 
00837   rc = CertGetCertificateContextProperty(certContext,
00838        CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size);
00839   if (!rc) {
00840     return;
00841   }
00842   io->idData = nss_ZNEWARRAY(NULL, char, size);
00843   if (io->idData == NULL) {
00844     return;
00845   }
00846 
00847   rc = CertGetCertificateContextProperty(certContext,
00848        CERT_KEY_IDENTIFIER_PROP_ID, io->idData, &size);
00849   if (!rc) {
00850     nss_ZFreeIf(io->idData);
00851     io->idData = NULL;
00852     return;
00853   }
00854   io->id.data = io->idData;
00855   io->id.size = size;
00856   return;
00857 }
00858 
00859 /*
00860  * fetch the hash key.
00861  */
00862 void
00863 ckcapi_CertFetchHashKey
00864 (
00865   ckcapiInternalObject *io
00866 )
00867 {
00868   ckcapiCertObject *co = &io->u.cert;
00869   PCCERT_CONTEXT certContext = io->u.cert.certContext;
00870   DWORD size = certContext->cbCertEncoded;
00871   DWORD max = sizeof(io->hashKeyData)-1;
00872   DWORD offset = 0;
00873 
00874   /* make sure we don't over flow. NOTE: cutting the top of a cert is
00875    * not a big issue because the signature for will be unique for the cert */
00876   if (size > max) {
00877     offset = size - max;
00878     size = max;
00879   }
00880 
00881   nsslibc_memcpy(io->hashKeyData,certContext->pbCertEncoded+offset, size);
00882   io->hashKeyData[size] = (char)(io->objClass & 0xff);
00883 
00884   io->hashKey.data = io->hashKeyData;
00885   io->hashKey.size = size+1;
00886   return;
00887 }
00888 
00889 /*
00890  * fetch the hash key.
00891  */
00892 void
00893 ckcapi_KeyFetchHashKey
00894 (
00895   ckcapiInternalObject *io
00896 )
00897 {
00898   ckcapiKeyObject *ko = &io->u.key;
00899   DWORD size;
00900   DWORD max = sizeof(io->hashKeyData)-2;
00901   DWORD offset = 0;
00902   DWORD provLen = strlen(ko->provName);
00903   DWORD containerLen = strlen(ko->containerName);
00904 
00905  
00906   size = provLen + containerLen; 
00907 
00908   /* make sure we don't overflow, try to keep things unique */
00909   if (size > max) {
00910     DWORD diff = ((size - max)+1)/2;
00911     provLen -= diff;
00912     containerLen -= diff;
00913     size = provLen+containerLen;
00914   }
00915 
00916   nsslibc_memcpy(io->hashKeyData, ko->provName, provLen);
00917   nsslibc_memcpy(&io->hashKeyData[provLen],
00918                  ko->containerName,
00919                containerLen);
00920   io->hashKeyData[size] = (char)(io->objClass & 0xff);
00921   io->hashKeyData[size+1] = (char)(ko->provInfo.dwKeySpec & 0xff);
00922 
00923   io->hashKey.data = io->hashKeyData;
00924   io->hashKey.size = size+2;
00925   return;
00926 }
00927 
00928 /*
00929  * fetch the hash key.
00930  */
00931 void
00932 ckcapi_FetchHashKey
00933 (
00934   ckcapiInternalObject *io
00935 )
00936 {
00937   if (ckcapiCert == io->type) {
00938     ckcapi_CertFetchHashKey(io);
00939   } else {
00940     ckcapi_KeyFetchHashKey(io);
00941   } 
00942   return;
00943 }
00944  
00945 const NSSItem *
00946 ckcapi_FetchCertAttribute
00947 (
00948   ckcapiInternalObject *io,
00949   CK_ATTRIBUTE_TYPE type
00950 )
00951 {
00952   PCCERT_CONTEXT certContext = io->u.cert.certContext;
00953   switch(type) {
00954   case CKA_CLASS:
00955     return &ckcapi_certClassItem;
00956   case CKA_TOKEN:
00957     return &ckcapi_trueItem;
00958   case CKA_MODIFIABLE:
00959   case CKA_PRIVATE:
00960     return &ckcapi_falseItem;
00961   case CKA_CERTIFICATE_TYPE:
00962     return &ckcapi_x509Item;
00963   case CKA_LABEL:
00964     if (0 == io->u.cert.label.size) {
00965       ckcapi_FetchLabel(io);
00966     }
00967     return &io->u.cert.label;
00968   case CKA_SUBJECT:
00969     if (0 == io->u.cert.subject.size) {
00970       io->u.cert.subject.data = certContext->pCertInfo->Subject.pbData;
00971       io->u.cert.subject.size = certContext->pCertInfo->Subject.cbData;
00972     }
00973     return &io->u.cert.subject;
00974   case CKA_ISSUER:
00975     if (0 == io->u.cert.issuer.size) {
00976       io->u.cert.issuer.data = certContext->pCertInfo->Issuer.pbData;
00977       io->u.cert.issuer.size = certContext->pCertInfo->Issuer.cbData;
00978     }
00979     return &io->u.cert.issuer;
00980   case CKA_SERIAL_NUMBER:
00981     if (0 == io->u.cert.serial.size) {
00982       /* not exactly right. This should be the encoded serial number, but
00983        * it's the decoded serial number! */
00984       ckcapi_FetchSerial(io);
00985     }
00986     return &io->u.cert.serial;
00987   case CKA_VALUE:
00988     if (0 == io->u.cert.derCert.size) {
00989       io->u.cert.derCert.data = io->u.cert.certContext->pbCertEncoded;
00990       io->u.cert.derCert.size = io->u.cert.certContext->cbCertEncoded;
00991     }
00992     return &io->u.cert.derCert;
00993   case CKA_ID:
00994     if (!io->u.cert.hasID) {
00995       return NULL;
00996     }
00997     if (0 == io->id.size) {
00998       ckcapi_FetchID(io);
00999     }
01000     return &io->id;
01001   default:
01002     break;
01003   }
01004   return NULL;
01005 }
01006 
01007 const NSSItem *
01008 ckcapi_FetchPubKeyAttribute
01009 (
01010   ckcapiInternalObject *io, 
01011   CK_ATTRIBUTE_TYPE type
01012 )
01013 {
01014   PRBool isCertType = (ckcapiCert == io->type);
01015   ckcapiKeyParams *kp = isCertType ? &io->u.cert.key : &io->u.key.key;
01016   
01017   switch(type) {
01018   case CKA_CLASS:
01019     return &ckcapi_pubKeyClassItem;
01020   case CKA_TOKEN:
01021   case CKA_LOCAL:
01022   case CKA_ENCRYPT:
01023   case CKA_VERIFY:
01024   case CKA_VERIFY_RECOVER:
01025     return &ckcapi_trueItem;
01026   case CKA_PRIVATE:
01027   case CKA_MODIFIABLE:
01028   case CKA_DERIVE:
01029   case CKA_WRAP:
01030     return &ckcapi_falseItem;
01031   case CKA_KEY_TYPE:
01032     return &ckcapi_rsaItem;
01033   case CKA_LABEL:
01034     if (!isCertType) {
01035       return &ckcapi_emptyItem;
01036     }
01037     if (0 == io->u.cert.label.size) {
01038       ckcapi_FetchLabel(io);
01039     }
01040     return &io->u.cert.label;
01041   case CKA_SUBJECT:
01042     if (!isCertType) {
01043       return &ckcapi_emptyItem;
01044     }
01045     if (0 == io->u.cert.subject.size) {
01046       PCCERT_CONTEXT certContext= io->u.cert.certContext;
01047       io->u.cert.subject.data = certContext->pCertInfo->Subject.pbData;
01048       io->u.cert.subject.size = certContext->pCertInfo->Subject.cbData;
01049     }
01050     return &io->u.cert.subject;
01051   case CKA_MODULUS:
01052     if (0 == kp->modulus.size) {
01053        ckcapi_PopulateModulusExponent(io);
01054     }
01055     return &kp->modulus;
01056   case CKA_PUBLIC_EXPONENT:
01057     if (0 == kp->modulus.size) {
01058        ckcapi_PopulateModulusExponent(io);
01059     }
01060     return &kp->exponent;
01061   case CKA_ID:
01062     if (0 == io->id.size) {
01063       ckcapi_FetchID(io);
01064     }
01065     return &io->id;
01066   default:
01067     break;
01068   }
01069   return NULL;
01070 }
01071 
01072 const NSSItem *
01073 ckcapi_FetchPrivKeyAttribute
01074 (
01075   ckcapiInternalObject *io, 
01076   CK_ATTRIBUTE_TYPE type
01077 )
01078 {
01079   PRBool isCertType = (ckcapiCert == io->type);
01080   ckcapiKeyParams *kp = isCertType ? &io->u.cert.key : &io->u.key.key;
01081 
01082   switch(type) {
01083   case CKA_CLASS:
01084     return &ckcapi_privKeyClassItem;
01085   case CKA_TOKEN:
01086   case CKA_LOCAL:
01087   case CKA_SIGN:
01088   case CKA_DECRYPT:
01089   case CKA_SIGN_RECOVER:
01090     return &ckcapi_trueItem;
01091   case CKA_SENSITIVE:
01092   case CKA_PRIVATE:    /* should move in the future */
01093   case CKA_MODIFIABLE:
01094   case CKA_DERIVE:
01095   case CKA_UNWRAP:
01096   case CKA_EXTRACTABLE: /* will probably move in the future */
01097   case CKA_ALWAYS_SENSITIVE:
01098   case CKA_NEVER_EXTRACTABLE:
01099     return &ckcapi_falseItem;
01100   case CKA_KEY_TYPE:
01101     return &ckcapi_rsaItem;
01102   case CKA_LABEL:
01103     if (!isCertType) {
01104       return &ckcapi_emptyItem;
01105     }
01106     if (0 == io->u.cert.label.size) {
01107       ckcapi_FetchLabel(io);
01108     }
01109     return &io->u.cert.label;
01110   case CKA_SUBJECT:
01111     if (!isCertType) {
01112       return &ckcapi_emptyItem;
01113     }
01114     if (0 == io->u.cert.subject.size) {
01115       PCCERT_CONTEXT certContext= io->u.cert.certContext;
01116       io->u.cert.subject.data = certContext->pCertInfo->Subject.pbData;
01117       io->u.cert.subject.size = certContext->pCertInfo->Subject.cbData;
01118     }
01119     return &io->u.cert.subject;
01120   case CKA_MODULUS:
01121     if (0 == kp->modulus.size) {
01122       ckcapi_PopulateModulusExponent(io);
01123     }
01124     return &kp->modulus;
01125   case CKA_PUBLIC_EXPONENT:
01126     if (0 == kp->modulus.size) {
01127       ckcapi_PopulateModulusExponent(io);
01128     }
01129     return &kp->exponent;
01130   case CKA_PRIVATE_EXPONENT:
01131     if (0 == kp->privateExponent.size) {
01132       ckcapi_FetchPrivateKey(io);
01133     }
01134     return &kp->privateExponent;
01135   case CKA_PRIME_1:
01136     if (0 == kp->privateExponent.size) {
01137       ckcapi_FetchPrivateKey(io);
01138     }
01139     return &kp->prime1;
01140   case CKA_PRIME_2:
01141     if (0 == kp->privateExponent.size) {
01142       ckcapi_FetchPrivateKey(io);
01143     }
01144     return &kp->prime2;
01145   case CKA_EXPONENT_1:
01146     if (0 == kp->privateExponent.size) {
01147       ckcapi_FetchPrivateKey(io);
01148     }
01149     return &kp->exponent1;
01150   case CKA_EXPONENT_2:
01151     if (0 == kp->privateExponent.size) {
01152       ckcapi_FetchPrivateKey(io);
01153     }
01154     return &kp->exponent2;
01155   case CKA_COEFFICIENT:
01156     if (0 == kp->privateExponent.size) {
01157       ckcapi_FetchPrivateKey(io);
01158     }
01159     return &kp->coefficient;
01160   case CKA_ID:
01161     if (0 == io->id.size) {
01162       ckcapi_FetchID(io);
01163     }
01164     return &io->id;
01165   default:
01166     return NULL;
01167   }
01168 }
01169 
01170 const NSSItem *
01171 nss_ckcapi_FetchAttribute
01172 (
01173   ckcapiInternalObject *io, 
01174   CK_ATTRIBUTE_TYPE type
01175 )
01176 {
01177   CK_ULONG i;
01178 
01179   if (io->type == ckcapiRaw) {
01180     for( i = 0; i < io->u.raw.n; i++ ) {
01181       if( type == io->u.raw.types[i] ) {
01182         return &io->u.raw.items[i];
01183       }
01184     }
01185     return NULL;
01186   }
01187   /* deal with the common attributes */
01188   switch (io->objClass) {
01189   case CKO_CERTIFICATE:
01190    return ckcapi_FetchCertAttribute(io, type); 
01191   case CKO_PRIVATE_KEY:
01192    return ckcapi_FetchPrivKeyAttribute(io, type); 
01193   case CKO_PUBLIC_KEY:
01194    return ckcapi_FetchPubKeyAttribute(io, type); 
01195   }
01196   return NULL;
01197 }
01198 
01199 /*
01200  * check to see if the certificate already exists
01201  */
01202 static PRBool
01203 ckcapi_cert_exists(
01204   NSSItem *value,
01205   ckcapiInternalObject **io
01206 )
01207 {
01208   int count,i;
01209   PRUint32 size = 0;
01210   ckcapiInternalObject **listp = NULL;
01211   CK_ATTRIBUTE myTemplate[2];
01212   CK_OBJECT_CLASS cert_class = CKO_CERTIFICATE;
01213   CK_ULONG templateCount = 2;
01214   CK_RV error;
01215   PRBool found = PR_FALSE;
01216 
01217   myTemplate[0].type = CKA_CLASS;
01218   myTemplate[0].pValue = &cert_class;
01219   myTemplate[0].ulValueLen = sizeof(cert_class);
01220   myTemplate[1].type = CKA_VALUE;
01221   myTemplate[1].pValue = value->data;
01222   myTemplate[1].ulValueLen = value->size;
01223 
01224   count = nss_ckcapi_collect_all_certs(myTemplate, templateCount, &listp, 
01225                      &size, 0, &error);
01226 
01227   /* free them */
01228   if (count > 1) {
01229     *io = listp[0];
01230     found = PR_TRUE;
01231   }
01232     
01233   for (i=1; i < count; i++) {
01234     nss_ckcapi_DestroyInternalObject(listp[i]);
01235   }
01236   nss_ZFreeIf(listp);
01237   return found;
01238 }
01239 
01240 static PRBool
01241 ckcapi_cert_hasEmail
01242 (
01243   PCCERT_CONTEXT certContext
01244 )
01245 {
01246   int count;
01247 
01248   count = CertGetNameString(certContext, CERT_NAME_EMAIL_TYPE, 
01249                             0, NULL, NULL, 0);
01250 
01251   return count > 1 ? PR_TRUE : PR_FALSE;
01252 }
01253 
01254 static PRBool
01255 ckcapi_cert_isRoot
01256 (
01257   PCCERT_CONTEXT certContext
01258 )
01259 {
01260   return CertCompareCertificateName(certContext->dwCertEncodingType,
01261        &certContext->pCertInfo->Issuer, &certContext->pCertInfo->Subject);
01262 }
01263 
01264 static PRBool
01265 ckcapi_cert_isCA
01266 (
01267   PCCERT_CONTEXT certContext
01268 )
01269 {
01270   PCERT_EXTENSION extension;
01271   CERT_BASIC_CONSTRAINTS2_INFO basicInfo;
01272   DWORD size = sizeof(basicInfo);
01273   BOOL rc;
01274 
01275   extension = CertFindExtension (szOID_BASIC_CONSTRAINTS,
01276                             certContext->pCertInfo->cExtension,
01277                             certContext->pCertInfo->rgExtension);
01278   if ((PCERT_EXTENSION) NULL == extension ) {
01279     return PR_FALSE;
01280   }
01281   rc = CryptDecodeObject(X509_ASN_ENCODING, szOID_BASIC_CONSTRAINTS2,
01282           extension->Value.pbData, extension->Value.cbData, 
01283           0, &basicInfo, &size);
01284   if (!rc) {
01285     return PR_FALSE;
01286   }
01287   return (PRBool) basicInfo.fCA;
01288 }
01289 
01290 static CRYPT_KEY_PROV_INFO *
01291 ckcapi_cert_getPrivateKeyInfo
01292 (
01293   PCCERT_CONTEXT certContext,
01294   NSSItem *keyID
01295 )
01296 {
01297   BOOL rc;
01298   CRYPT_HASH_BLOB msKeyID;
01299   DWORD size = 0;
01300   CRYPT_KEY_PROV_INFO *prov = NULL;
01301 
01302   msKeyID.cbData = keyID->size;
01303   msKeyID.pbData = keyID->data;
01304 
01305   rc = CryptGetKeyIdentifierProperty(
01306          &msKeyID,
01307                 CERT_KEY_PROV_INFO_PROP_ID,
01308          0, NULL, NULL, NULL, &size);
01309   if (!rc) {
01310     return (CRYPT_KEY_PROV_INFO *)NULL;
01311   }
01312   prov = (CRYPT_KEY_PROV_INFO *)nss_ZAlloc(NULL, size);
01313   if ((CRYPT_KEY_PROV_INFO *)prov == NULL) {
01314     return (CRYPT_KEY_PROV_INFO *) NULL;
01315   }
01316   rc = CryptGetKeyIdentifierProperty(
01317          &msKeyID,
01318                 CERT_KEY_PROV_INFO_PROP_ID,
01319          0, NULL, NULL, prov, &size);
01320   if (!rc) {
01321     nss_ZFreeIf(prov);
01322     return (CRYPT_KEY_PROV_INFO *)NULL;
01323   }
01324   
01325   return prov;
01326 }
01327 
01328 static CRYPT_KEY_PROV_INFO *
01329 ckcapi_cert_getProvInfo
01330 (
01331   ckcapiInternalObject *io
01332 )
01333 {
01334   BOOL rc;
01335   DWORD size = 0;
01336   CRYPT_KEY_PROV_INFO *prov = NULL;
01337 
01338   rc = CertGetCertificateContextProperty(
01339          io->u.cert.certContext,
01340                 CERT_KEY_PROV_INFO_PROP_ID,
01341          NULL, &size);
01342   if (!rc) {
01343     return (CRYPT_KEY_PROV_INFO *)NULL;
01344   }
01345   prov = (CRYPT_KEY_PROV_INFO *)nss_ZAlloc(NULL, size);
01346   if ((CRYPT_KEY_PROV_INFO *)prov == NULL) {
01347     return (CRYPT_KEY_PROV_INFO *) NULL;
01348   }
01349   rc = CertGetCertificateContextProperty(
01350          io->u.cert.certContext,
01351                 CERT_KEY_PROV_INFO_PROP_ID,
01352          prov, &size);
01353   if (!rc) {
01354     nss_ZFreeIf(prov);
01355     return (CRYPT_KEY_PROV_INFO *)NULL;
01356   }
01357 
01358   return prov;
01359 }
01360   
01361 /* forward declaration */
01362 static void
01363 ckcapi_removeObjectFromHash
01364 (
01365   ckcapiInternalObject *io
01366 );
01367 
01368 /*
01369  * Finalize - unneeded
01370  * Destroy 
01371  * IsTokenObject - CK_TRUE
01372  * GetAttributeCount
01373  * GetAttributeTypes
01374  * GetAttributeSize
01375  * GetAttribute
01376  * SetAttribute
01377  * GetObjectSize
01378  */
01379 
01380 static CK_RV
01381 ckcapi_mdObject_Destroy
01382 (
01383   NSSCKMDObject *mdObject,
01384   NSSCKFWObject *fwObject,
01385   NSSCKMDSession *mdSession,
01386   NSSCKFWSession *fwSession,
01387   NSSCKMDToken *mdToken,
01388   NSSCKFWToken *fwToken,
01389   NSSCKMDInstance *mdInstance,
01390   NSSCKFWInstance *fwInstance
01391 )
01392 {
01393   ckcapiInternalObject *io = (ckcapiInternalObject *)mdObject->etc;
01394   CK_OBJECT_CLASS objClass;
01395   BOOL rc;
01396   DWORD provType;
01397   DWORD msError;
01398   PRBool isCertType = (PRBool)(ckcapiCert == io->type);
01399   HCERTSTORE hStore = 0;
01400 
01401   if (ckcapiRaw == io->type) {
01402     /* there is not 'object write protected' error, use the next best thing */
01403     return CKR_TOKEN_WRITE_PROTECTED;
01404   }
01405 
01406   objClass = io->objClass;
01407   if (CKO_CERTIFICATE == objClass) {
01408     PCCERT_CONTEXT certContext;
01409 
01410     /* get the store */
01411     hStore = CertOpenSystemStore(0, io->u.cert.certStore);
01412     if (0 == hStore) {
01413       rc = 0;
01414       goto loser;
01415     }
01416     certContext = CertFindCertificateInStore(hStore, X509_ASN_ENCODING, 0, 
01417       CERT_FIND_EXISTING, io->u.cert.certContext, NULL); 
01418     if ((PCCERT_CONTEXT)NULL ==  certContext) {
01419       rc = 0;
01420       goto loser;
01421     }
01422     rc = CertDeleteCertificateFromStore(certContext);
01423     CertFreeCertificateContext(certContext);
01424   } else {
01425     char *provName = NULL;
01426     char *containerName = NULL;
01427     HCRYPTPROV hProv;
01428     CRYPT_HASH_BLOB msKeyID;
01429 
01430     if (0 == io->id.size) {
01431       ckcapi_FetchID(io);
01432     }
01433 
01434     if (isCertType) {
01435       CRYPT_KEY_PROV_INFO * provInfo = ckcapi_cert_getProvInfo(io);
01436       provName = nss_ckcapi_WideToUTF8(provInfo->pwszProvName);
01437       containerName = nss_ckcapi_WideToUTF8(provInfo->pwszContainerName);
01438       provType = provInfo->dwProvType;
01439       nss_ZFreeIf(provInfo);
01440     } else {
01441       provName = io->u.key.provName;
01442       containerName = io->u.key.containerName;
01443       provType = io->u.key.provInfo.dwProvType;
01444       io->u.key.provName = NULL;
01445       io->u.key.containerName = NULL;
01446     }
01447     /* first remove the key id pointer */
01448     msKeyID.cbData = io->id.size;
01449     msKeyID.pbData = io->id.data;
01450     rc = CryptSetKeyIdentifierProperty(&msKeyID, 
01451        CERT_KEY_PROV_INFO_PROP_ID, CRYPT_KEYID_DELETE_FLAG, NULL, NULL, NULL);
01452     if (rc) {
01453       rc = CryptAcquireContext(&hProv, containerName, provName, provType,
01454               CRYPT_DELETEKEYSET);
01455     }
01456     nss_ZFreeIf(provName);
01457     nss_ZFreeIf(containerName);
01458   }
01459 loser:
01460 
01461   if (hStore) {
01462     CertCloseStore(hStore, 0);
01463   }
01464   if (!rc) {
01465     msError = GetLastError();
01466     return CKR_GENERAL_ERROR;
01467   }
01468 
01469   /* remove it from the hash */
01470   ckcapi_removeObjectFromHash(io);
01471 
01472   /* free the puppy.. */
01473   nss_ckcapi_DestroyInternalObject(io);
01474   return CKR_OK;
01475 }
01476 
01477 static CK_BBOOL
01478 ckcapi_mdObject_IsTokenObject
01479 (
01480   NSSCKMDObject *mdObject,
01481   NSSCKFWObject *fwObject,
01482   NSSCKMDSession *mdSession,
01483   NSSCKFWSession *fwSession,
01484   NSSCKMDToken *mdToken,
01485   NSSCKFWToken *fwToken,
01486   NSSCKMDInstance *mdInstance,
01487   NSSCKFWInstance *fwInstance
01488 )
01489 {
01490   return CK_TRUE;
01491 }
01492 
01493 static CK_ULONG
01494 ckcapi_mdObject_GetAttributeCount
01495 (
01496   NSSCKMDObject *mdObject,
01497   NSSCKFWObject *fwObject,
01498   NSSCKMDSession *mdSession,
01499   NSSCKFWSession *fwSession,
01500   NSSCKMDToken *mdToken,
01501   NSSCKFWToken *fwToken,
01502   NSSCKMDInstance *mdInstance,
01503   NSSCKFWInstance *fwInstance,
01504   CK_RV *pError
01505 )
01506 {
01507   ckcapiInternalObject *io = (ckcapiInternalObject *)mdObject->etc;
01508 
01509   if (ckcapiRaw == io->type) {
01510      return io->u.raw.n;
01511   }
01512   switch (io->objClass) {
01513   case CKO_CERTIFICATE:
01514     return certAttrsCount;
01515   case CKO_PUBLIC_KEY:
01516     return pubKeyAttrsCount;
01517   case CKO_PRIVATE_KEY:
01518     return privKeyAttrsCount;
01519   default:
01520     break;
01521   }
01522   return 0;
01523 }
01524 
01525 static CK_RV
01526 ckcapi_mdObject_GetAttributeTypes
01527 (
01528   NSSCKMDObject *mdObject,
01529   NSSCKFWObject *fwObject,
01530   NSSCKMDSession *mdSession,
01531   NSSCKFWSession *fwSession,
01532   NSSCKMDToken *mdToken,
01533   NSSCKFWToken *fwToken,
01534   NSSCKMDInstance *mdInstance,
01535   NSSCKFWInstance *fwInstance,
01536   CK_ATTRIBUTE_TYPE_PTR typeArray,
01537   CK_ULONG ulCount
01538 )
01539 {
01540   ckcapiInternalObject *io = (ckcapiInternalObject *)mdObject->etc;
01541   CK_ULONG i;
01542   CK_RV error = CKR_OK;
01543   const CK_ATTRIBUTE_TYPE *attrs = NULL;
01544   CK_ULONG size = ckcapi_mdObject_GetAttributeCount(
01545                      mdObject, fwObject, mdSession, fwSession, 
01546                      mdToken, fwToken, mdInstance, fwInstance, &error);
01547 
01548   if( size != ulCount ) {
01549     return CKR_BUFFER_TOO_SMALL;
01550   }
01551   if (io->type == ckcapiRaw) {
01552     attrs = io->u.raw.types;
01553   } else switch(io->objClass) {
01554     case CKO_CERTIFICATE:
01555       attrs = certAttrs;
01556       break;
01557     case CKO_PUBLIC_KEY:
01558       attrs = pubKeyAttrs;
01559       break;
01560     case CKO_PRIVATE_KEY:
01561       attrs = privKeyAttrs;
01562       break;
01563     default:
01564       return CKR_OK;
01565   }
01566   
01567   for( i = 0; i < size; i++) {
01568     typeArray[i] = attrs[i];
01569   }
01570 
01571   return CKR_OK;
01572 }
01573 
01574 static CK_ULONG
01575 ckcapi_mdObject_GetAttributeSize
01576 (
01577   NSSCKMDObject *mdObject,
01578   NSSCKFWObject *fwObject,
01579   NSSCKMDSession *mdSession,
01580   NSSCKFWSession *fwSession,
01581   NSSCKMDToken *mdToken,
01582   NSSCKFWToken *fwToken,
01583   NSSCKMDInstance *mdInstance,
01584   NSSCKFWInstance *fwInstance,
01585   CK_ATTRIBUTE_TYPE attribute,
01586   CK_RV *pError
01587 )
01588 {
01589   ckcapiInternalObject *io = (ckcapiInternalObject *)mdObject->etc;
01590 
01591   const NSSItem *b;
01592 
01593   b = nss_ckcapi_FetchAttribute(io, attribute);
01594 
01595   if ((const NSSItem *)NULL == b) {
01596     *pError = CKR_ATTRIBUTE_TYPE_INVALID;
01597     return 0;
01598   }
01599   return b->size;
01600 }
01601 
01602 static CK_RV
01603 ckcapi_mdObject_SetAttribute
01604 (
01605   NSSCKMDObject *mdObject,
01606   NSSCKFWObject *fwObject,
01607   NSSCKMDSession *mdSession,
01608   NSSCKFWSession *fwSession,
01609   NSSCKMDToken *mdToken,
01610   NSSCKFWToken *fwToken,
01611   NSSCKMDInstance *mdInstance,
01612   NSSCKFWInstance *fwInstance,
01613   CK_ATTRIBUTE_TYPE attribute,
01614   NSSItem           *value
01615 )
01616 {
01617   return CKR_OK;
01618 }
01619 
01620 static NSSCKFWItem
01621 ckcapi_mdObject_GetAttribute
01622 (
01623   NSSCKMDObject *mdObject,
01624   NSSCKFWObject *fwObject,
01625   NSSCKMDSession *mdSession,
01626   NSSCKFWSession *fwSession,
01627   NSSCKMDToken *mdToken,
01628   NSSCKFWToken *fwToken,
01629   NSSCKMDInstance *mdInstance,
01630   NSSCKFWInstance *fwInstance,
01631   CK_ATTRIBUTE_TYPE attribute,
01632   CK_RV *pError
01633 )
01634 {
01635   NSSCKFWItem mdItem;
01636   ckcapiInternalObject *io = (ckcapiInternalObject *)mdObject->etc;
01637 
01638   mdItem.needsFreeing = PR_FALSE;
01639   mdItem.item = (NSSItem*)nss_ckcapi_FetchAttribute(io, attribute);
01640 
01641   if ((NSSItem *)NULL == mdItem.item) {
01642     *pError = CKR_ATTRIBUTE_TYPE_INVALID;
01643   }
01644 
01645   return mdItem;
01646 }
01647 
01648 static CK_ULONG
01649 ckcapi_mdObject_GetObjectSize
01650 (
01651   NSSCKMDObject *mdObject,
01652   NSSCKFWObject *fwObject,
01653   NSSCKMDSession *mdSession,
01654   NSSCKFWSession *fwSession,
01655   NSSCKMDToken *mdToken,
01656   NSSCKFWToken *fwToken,
01657   NSSCKMDInstance *mdInstance,
01658   NSSCKFWInstance *fwInstance,
01659   CK_RV *pError
01660 )
01661 {
01662   ckcapiInternalObject *io = (ckcapiInternalObject *)mdObject->etc;
01663   CK_ULONG rv = 1;
01664 
01665   /* size is irrelevant to this token */
01666   return rv;
01667 }
01668 
01669 static const NSSCKMDObject
01670 ckcapi_prototype_mdObject = {
01671   (void *)NULL, /* etc */
01672   NULL, /* Finalize */
01673   ckcapi_mdObject_Destroy,
01674   ckcapi_mdObject_IsTokenObject,
01675   ckcapi_mdObject_GetAttributeCount,
01676   ckcapi_mdObject_GetAttributeTypes,
01677   ckcapi_mdObject_GetAttributeSize,
01678   ckcapi_mdObject_GetAttribute,
01679   NULL, /* FreeAttribute */
01680   ckcapi_mdObject_SetAttribute,
01681   ckcapi_mdObject_GetObjectSize,
01682   (void *)NULL /* null terminator */
01683 };
01684 
01685 static nssHash *ckcapiInternalObjectHash = NULL;
01686 
01687 NSS_IMPLEMENT NSSCKMDObject *
01688 nss_ckcapi_CreateMDObject
01689 (
01690   NSSArena *arena,
01691   ckcapiInternalObject *io,
01692   CK_RV *pError
01693 )
01694 {
01695   if ((nssHash *)NULL == ckcapiInternalObjectHash) {
01696     ckcapiInternalObjectHash = nssHash_CreateItem(NULL, 10);
01697   }
01698   if (ckcapiCert == io->type) {
01699     /* the hash key, not a cryptographic key */
01700     NSSItem *key = &io->hashKey;
01701     ckcapiInternalObject *old_o = NULL;
01702 
01703     if (key->size == 0) {
01704       ckcapi_FetchHashKey(io);
01705     }
01706     old_o = (ckcapiInternalObject *) 
01707               nssHash_Lookup(ckcapiInternalObjectHash, key);
01708     if (!old_o) {
01709       nssHash_Add(ckcapiInternalObjectHash, key, io);
01710     } else if (old_o != io) {
01711       nss_ckcapi_DestroyInternalObject(io);
01712       io = old_o;
01713     }
01714   }
01715     
01716   if ( (void*)NULL == io->mdObject.etc) {
01717     (void) nsslibc_memcpy(&io->mdObject,&ckcapi_prototype_mdObject,
01718                                    sizeof(ckcapi_prototype_mdObject));
01719     io->mdObject.etc = (void *)io;
01720   }
01721   return &io->mdObject;
01722 }
01723 
01724 static void
01725 ckcapi_removeObjectFromHash
01726 (
01727   ckcapiInternalObject *io
01728 )
01729 {
01730   NSSItem *key = &io->hashKey;
01731 
01732   if ((nssHash *)NULL == ckcapiInternalObjectHash) {
01733     return;
01734   }
01735   if (key->size == 0) {
01736     ckcapi_FetchHashKey(io);
01737   }
01738   nssHash_Remove(ckcapiInternalObjectHash, key);
01739   return;
01740 }
01741 
01742 void
01743 nss_ckcapi_DestroyInternalObject
01744 (
01745   ckcapiInternalObject *io
01746 )
01747 {
01748   switch (io->type) {
01749   case ckcapiRaw:
01750     return;
01751   case ckcapiCert:
01752     CertFreeCertificateContext(io->u.cert.certContext);
01753     nss_ZFreeIf(io->u.cert.labelData);
01754     nss_ZFreeIf(io->u.cert.key.privateKey);
01755     nss_ZFreeIf(io->u.cert.key.pubKey);
01756     nss_ZFreeIf(io->idData);
01757     break;
01758   case ckcapiBareKey:
01759     nss_ZFreeIf(io->u.key.provInfo.pwszContainerName);
01760     nss_ZFreeIf(io->u.key.provInfo.pwszProvName);
01761     nss_ZFreeIf(io->u.key.provName);
01762     nss_ZFreeIf(io->u.key.containerName);
01763     nss_ZFreeIf(io->u.key.key.privateKey);
01764     nss_ZFreeIf(io->u.key.key.pubKey);
01765     if (0 != io->u.key.hProv) {
01766       CryptReleaseContext(io->u.key.hProv, 0);
01767     }
01768     nss_ZFreeIf(io->idData);
01769     break;
01770   }
01771   nss_ZFreeIf(io);
01772   return;
01773 }
01774 
01775 static ckcapiInternalObject *
01776 nss_ckcapi_CreateCertificate
01777 (
01778   NSSCKFWSession *fwSession,
01779   CK_ATTRIBUTE_PTR pTemplate,
01780   CK_ULONG ulAttributeCount,
01781   CK_RV *pError
01782 )
01783 {
01784   NSSItem value;
01785   NSSItem keyID;
01786   char *storeStr;
01787   ckcapiInternalObject *io = NULL;
01788   PCCERT_CONTEXT certContext = NULL;
01789   PCCERT_CONTEXT storedCertContext = NULL;
01790   CRYPT_KEY_PROV_INFO *prov_info = NULL;
01791   char *nickname = NULL;
01792   HCERTSTORE hStore = 0;
01793   DWORD msError = 0;
01794   PRBool hasID;
01795   CK_RV dummy;
01796   BOOL rc;
01797 
01798   *pError = nss_ckcapi_GetAttribute(CKA_VALUE, pTemplate, 
01799                               ulAttributeCount, &value);
01800 
01801   if (CKR_OK != *pError) {
01802     return (ckcapiInternalObject *)NULL;
01803   }
01804 
01805   *pError = nss_ckcapi_GetAttribute(CKA_ID, pTemplate, 
01806                               ulAttributeCount, &keyID);
01807 
01808   if (CKR_OK != *pError) {
01809     return (ckcapiInternalObject *)NULL;
01810   }
01811 
01812   if (ckcapi_cert_exists(&value, &io)) {
01813     return io;
01814   }
01815 
01816   /* OK, we are creating a new one, figure out what store it belongs to.. 
01817    * first get a certContext handle.. */
01818   certContext = CertCreateCertificateContext(X509_ASN_ENCODING, 
01819                                              value.data, value.size);
01820   if ((PCCERT_CONTEXT) NULL == certContext) {
01821     msError = GetLastError();
01822     *pError = CKR_ATTRIBUTE_VALUE_INVALID;
01823     goto loser;
01824   }
01825 
01826   /* do we have a private key laying around... */
01827   prov_info = ckcapi_cert_getPrivateKeyInfo(certContext, &keyID);
01828   if (prov_info) {
01829     CRYPT_DATA_BLOB msKeyID;
01830     storeStr = "My";
01831     hasID = PR_TRUE;
01832     rc = CertSetCertificateContextProperty(certContext,
01833                       CERT_KEY_PROV_INFO_PROP_ID,
01834                 0, prov_info);
01835     nss_ZFreeIf(prov_info);
01836     if (!rc) {
01837       msError = GetLastError();
01838       *pError = CKR_DEVICE_ERROR;
01839       goto loser;
01840     }
01841     msKeyID.cbData = keyID.size;
01842     msKeyID.pbData = keyID.data;
01843     rc = CertSetCertificateContextProperty(certContext,
01844                       CERT_KEY_IDENTIFIER_PROP_ID,
01845                 0, &msKeyID);
01846     if (!rc) {
01847       msError = GetLastError();
01848       *pError = CKR_DEVICE_ERROR;
01849       goto loser;
01850     }
01851     
01852   /* does it look like a CA */
01853   } else if (ckcapi_cert_isCA(certContext)) {
01854     storeStr = ckcapi_cert_isRoot(certContext) ? "CA" : "Root";
01855   /* does it look like an S/MIME cert */
01856   } else if (ckcapi_cert_hasEmail(certContext)) {
01857     storeStr = "AddressBook";
01858   } else {
01859   /* just pick a store */
01860     storeStr = "CA";
01861   }
01862 
01863   /* get the nickname, not an error if we can't find it */
01864   nickname = nss_ckcapi_GetStringAttribute(CKA_LABEL, pTemplate, 
01865                               ulAttributeCount, &dummy);
01866   if (nickname) {
01867     LPWSTR nicknameUTF16 = NULL;
01868     CRYPT_DATA_BLOB nicknameBlob;
01869 
01870     nicknameUTF16 = nss_ckcapi_UTF8ToWide(nickname);
01871     nss_ZFreeIf(nickname);
01872     nickname = NULL;
01873     if ((LPWSTR)NULL == nicknameUTF16) {
01874       *pError = CKR_HOST_MEMORY;
01875       goto loser;
01876     }
01877     nicknameBlob.cbData = nss_ckcapi_WideSize(nicknameUTF16);
01878     nicknameBlob.pbData = (BYTE *)nicknameUTF16;
01879     rc = CertSetCertificateContextProperty(certContext,
01880        CERT_FRIENDLY_NAME_PROP_ID, 0, &nicknameBlob);
01881     nss_ZFreeIf(nicknameUTF16);
01882     if (!rc) {
01883       msError = GetLastError();
01884       *pError = CKR_DEVICE_ERROR;
01885       goto loser;
01886     }
01887   }
01888 
01889   hStore = CertOpenSystemStore((HCRYPTPROV) NULL, storeStr);
01890   if (0 == hStore) {
01891     msError = GetLastError();
01892     *pError = CKR_DEVICE_ERROR;
01893     goto loser;
01894   }
01895 
01896   rc = CertAddCertificateContextToStore(hStore, certContext, 
01897        CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES, &storedCertContext);
01898   CertFreeCertificateContext(certContext);
01899   certContext = NULL;
01900   CertCloseStore(hStore, 0);
01901   hStore = 0;
01902   if (!rc) {
01903     msError = GetLastError();
01904     *pError = CKR_DEVICE_ERROR;
01905     goto loser;
01906   }
01907 
01908   io = nss_ZNEW(NULL, ckcapiInternalObject);
01909   if ((ckcapiInternalObject *)NULL == io) {
01910     *pError = CKR_HOST_MEMORY;
01911     goto loser;
01912   }
01913   io->type = ckcapiCert;
01914   io->objClass = CKO_CERTIFICATE;
01915   io->u.cert.certContext = storedCertContext;
01916   io->u.cert.hasID = hasID;
01917   return io;
01918 
01919 loser:
01920   if (certContext) {
01921     CertFreeCertificateContext(certContext);
01922     certContext = NULL;
01923   }
01924   if (storedCertContext) {
01925     CertFreeCertificateContext(storedCertContext);
01926     storedCertContext = NULL;
01927   }
01928   if (0 != hStore) {
01929     CertCloseStore(hStore, 0);
01930   }
01931   return (ckcapiInternalObject *)NULL;
01932 
01933 }
01934 
01935 static char *
01936 ckcapi_getDefaultProvider
01937 (
01938   CK_RV *pError
01939 )
01940 {
01941   char *name = NULL;
01942   BOOL rc;
01943   DWORD nameLength = 0;
01944 
01945   rc = CryptGetDefaultProvider(PROV_RSA_FULL, NULL, CRYPT_USER_DEFAULT, NULL,
01946               &nameLength);
01947   if (!rc) {
01948     return (char *)NULL;
01949   }
01950 
01951   name = nss_ZNEWARRAY(NULL, char, nameLength);
01952   if ((char *)NULL == name ) {
01953     return (char *)NULL;
01954   }
01955   rc = CryptGetDefaultProvider(PROV_RSA_FULL, NULL, CRYPT_USER_DEFAULT, name,
01956               &nameLength);
01957   if (!rc) {
01958     nss_ZFreeIf(name);
01959     return (char *)NULL;
01960   }
01961 
01962   return name;
01963 }
01964 
01965 static char *
01966 ckcapi_getContainer
01967 (
01968   CK_RV *pError,
01969   NSSItem *id
01970 )
01971 {
01972   RPC_STATUS rstat;
01973   UUID uuid;
01974   char *uuidStr;
01975   char *container;
01976 
01977   rstat = UuidCreate(&uuid);
01978   rstat = UuidToString(&uuid, &uuidStr);
01979 
01980   /* convert it from rcp memory to our own */
01981   container = nssUTF8_Duplicate(uuidStr, NULL);
01982   RpcStringFree(&uuidStr);
01983   
01984   return container;
01985 }
01986 
01987 static CK_RV
01988 ckcapi_buildPrivateKeyBlob
01989 (
01990   NSSItem  *keyBlob, 
01991   NSSItem  *modulus,
01992   NSSItem  *publicExponent,
01993   NSSItem  *privateExponent,
01994   NSSItem  *prime1,
01995   NSSItem  *prime2,
01996   NSSItem  *exponent1,
01997   NSSItem  *exponent2,
01998   NSSItem  *coefficient, 
01999   PRBool   isKeyExchange
02000 )
02001 {
02002   CAPI_RSA_KEY_BLOB *keyBlobData = NULL;
02003   unsigned char *target;
02004   unsigned long modSize = modulus->size;
02005   unsigned long dataSize;
02006   CK_RV error = CKR_OK;
02007 
02008   /* validate extras */
02009   if (privateExponent->size != modSize) {
02010     error = CKR_ATTRIBUTE_VALUE_INVALID;
02011     goto loser;
02012   }
02013   if (prime1->size != modSize/2) {
02014     error = CKR_ATTRIBUTE_VALUE_INVALID;
02015     goto loser;
02016   }
02017   if (prime2->size != modSize/2) {
02018     error = CKR_ATTRIBUTE_VALUE_INVALID;
02019     goto loser;
02020   }
02021   if (exponent1->size != modSize/2) {
02022     error = CKR_ATTRIBUTE_VALUE_INVALID;
02023     goto loser;
02024   }
02025   if (exponent2->size != modSize/2) {
02026     error = CKR_ATTRIBUTE_VALUE_INVALID;
02027     goto loser;
02028   }
02029   if (coefficient->size != modSize/2) {
02030     error = CKR_ATTRIBUTE_VALUE_INVALID;
02031     goto loser;
02032   }
02033   dataSize = (modSize*4)+(modSize/2) + sizeof(CAPI_RSA_KEY_BLOB);
02034   keyBlobData = (CAPI_RSA_KEY_BLOB *)nss_ZAlloc(NULL, dataSize);
02035   if ((CAPI_RSA_KEY_BLOB *)NULL == keyBlobData) {
02036     error = CKR_HOST_MEMORY;
02037     goto loser;
02038   }
02039 
02040   keyBlobData->header.bType = PRIVATEKEYBLOB;
02041   keyBlobData->header.bVersion = 0x02;
02042   keyBlobData->header.reserved = 0x00;
02043   keyBlobData->header.aiKeyAlg = isKeyExchange ? CALG_RSA_KEYX:CALG_RSA_SIGN;
02044   keyBlobData->rsa.magic = 0x32415352;
02045   keyBlobData->rsa.bitlen = modSize * 8;
02046   keyBlobData->rsa.pubexp = nss_ckcapi_DataToInt(publicExponent,&error);
02047   if (CKR_OK != error) {
02048     goto loser;
02049   }
02050 
02051   target = &keyBlobData->data[CAPI_MODULUS_OFFSET(modSize)];
02052   nsslibc_memcpy(target, modulus->data, modulus->size);
02053   modulus->data = target;
02054   ckcapi_ReverseData(modulus);
02055 
02056   target = &keyBlobData->data[CAPI_PRIVATE_EXP_OFFSET(modSize)];
02057   nsslibc_memcpy(target, privateExponent->data, privateExponent->size);
02058   privateExponent->data = target;
02059   ckcapi_ReverseData(privateExponent);
02060 
02061   target = &keyBlobData->data[CAPI_PRIME_1_OFFSET(modSize)];
02062   nsslibc_memcpy(target, prime1->data, prime1->size);
02063   prime1->data = target;
02064   ckcapi_ReverseData(prime1);
02065 
02066   target = &keyBlobData->data[CAPI_PRIME_2_OFFSET(modSize)];
02067   nsslibc_memcpy(target, prime2->data, prime2->size);
02068   prime2->data = target;
02069   ckcapi_ReverseData(prime2);
02070 
02071   target = &keyBlobData->data[CAPI_EXPONENT_1_OFFSET(modSize)];
02072   nsslibc_memcpy(target, exponent1->data, exponent1->size);
02073   exponent1->data = target;
02074   ckcapi_ReverseData(exponent1);
02075 
02076   target = &keyBlobData->data[CAPI_EXPONENT_2_OFFSET(modSize)];
02077   nsslibc_memcpy(target, exponent2->data, exponent2->size);
02078   exponent2->data = target;
02079   ckcapi_ReverseData(exponent2);
02080 
02081   target = &keyBlobData->data[CAPI_COEFFICIENT_OFFSET(modSize)];
02082   nsslibc_memcpy(target, coefficient->data, coefficient->size);
02083   coefficient->data = target;
02084   ckcapi_ReverseData(coefficient);
02085 
02086   keyBlob->data = keyBlobData;
02087   keyBlob->size = dataSize;
02088 
02089   return CKR_OK;
02090 
02091 loser:
02092   nss_ZFreeIf(keyBlobData);
02093   return error;
02094 }
02095 
02096 static ckcapiInternalObject *
02097 nss_ckcapi_CreatePrivateKey
02098 (
02099   NSSCKFWSession *fwSession,
02100   CK_ATTRIBUTE_PTR pTemplate,
02101   CK_ULONG ulAttributeCount,
02102   CK_RV *pError
02103 )
02104 {
02105   NSSItem modulus;
02106   NSSItem publicExponent;
02107   NSSItem privateExponent;
02108   NSSItem exponent1;
02109   NSSItem exponent2;
02110   NSSItem prime1;
02111   NSSItem prime2;
02112   NSSItem coefficient;
02113   NSSItem keyID;
02114   NSSItem keyBlob;
02115   ckcapiInternalObject *io = NULL;
02116   char *providerName = NULL;
02117   char *containerName = NULL;
02118   char *idData = NULL;
02119   CRYPT_KEY_PROV_INFO provInfo;
02120   CRYPT_HASH_BLOB msKeyID;
02121   CK_KEY_TYPE keyType;
02122   HCRYPTPROV hProv = 0;
02123   HCRYPTKEY hKey = 0;
02124   PRBool decrypt;
02125   DWORD keySpec;
02126   DWORD msError;
02127   BOOL rc;
02128 
02129   keyType = nss_ckcapi_GetULongAttribute
02130                   (CKA_KEY_TYPE, pTemplate, ulAttributeCount, pError);
02131   if (CKR_OK != *pError) {
02132     return (ckcapiInternalObject *)NULL;
02133   }
02134   if (CKK_RSA != keyType) {
02135     *pError = CKR_ATTRIBUTE_VALUE_INVALID;
02136     return (ckcapiInternalObject *)NULL;
02137   }
02138 
02139   decrypt = nss_ckcapi_GetBoolAttribute(CKA_DECRYPT, 
02140                             pTemplate, ulAttributeCount, pError);
02141   if (CKR_TEMPLATE_INCOMPLETE == *pError) {
02142     decrypt = PR_TRUE; /* default to true */
02143   }
02144   decrypt = decrypt || nss_ckcapi_GetBoolAttribute(CKA_UNWRAP, 
02145                             pTemplate, ulAttributeCount, pError);
02146   if (CKR_TEMPLATE_INCOMPLETE == *pError) {
02147     decrypt = PR_TRUE; /* default to true */
02148   }
02149   keySpec = decrypt ? AT_KEYEXCHANGE : AT_SIGNATURE;
02150 
02151   *pError = nss_ckcapi_GetAttribute(CKA_MODULUS, pTemplate, 
02152                               ulAttributeCount, &modulus);
02153   if (CKR_OK != *pError) {
02154     return (ckcapiInternalObject *)NULL;
02155   }
02156   *pError = nss_ckcapi_GetAttribute(CKA_PUBLIC_EXPONENT, pTemplate, 
02157                               ulAttributeCount, &publicExponent);
02158   if (CKR_OK != *pError) {
02159     return (ckcapiInternalObject *)NULL;
02160   }
02161   *pError = nss_ckcapi_GetAttribute(CKA_PRIVATE_EXPONENT, pTemplate, 
02162                               ulAttributeCount, &privateExponent);
02163   if (CKR_OK != *pError) {
02164     return (ckcapiInternalObject *)NULL;
02165   }
02166   *pError = nss_ckcapi_GetAttribute(CKA_PRIME_1, pTemplate, 
02167                               ulAttributeCount, &prime1);
02168   if (CKR_OK != *pError) {
02169     return (ckcapiInternalObject *)NULL;
02170   }
02171   *pError = nss_ckcapi_GetAttribute(CKA_PRIME_2, pTemplate, 
02172                               ulAttributeCount, &prime2);
02173   if (CKR_OK != *pError) {
02174     return (ckcapiInternalObject *)NULL;
02175   }
02176   *pError = nss_ckcapi_GetAttribute(CKA_EXPONENT_1, pTemplate, 
02177                               ulAttributeCount, &exponent1);
02178   if (CKR_OK != *pError) {
02179     return (ckcapiInternalObject *)NULL;
02180   }
02181   *pError = nss_ckcapi_GetAttribute(CKA_EXPONENT_2, pTemplate, 
02182                               ulAttributeCount, &exponent2);
02183   if (CKR_OK != *pError) {
02184     return (ckcapiInternalObject *)NULL;
02185   }
02186   *pError = nss_ckcapi_GetAttribute(CKA_COEFFICIENT, pTemplate, 
02187                               ulAttributeCount, &coefficient);
02188   if (CKR_OK != *pError) {
02189     return (ckcapiInternalObject *)NULL;
02190   }
02191   *pError = nss_ckcapi_GetAttribute(CKA_ID, pTemplate, 
02192                               ulAttributeCount, &keyID);
02193   if (CKR_OK != *pError) {
02194     return (ckcapiInternalObject *)NULL;
02195   }
02196   providerName = ckcapi_getDefaultProvider(pError);
02197   if ((char *)NULL == providerName ) {
02198     return (ckcapiInternalObject *)NULL;
02199   }
02200   containerName = ckcapi_getContainer(pError, &keyID);
02201   if ((char *)NULL == providerName ) {
02202     goto loser;
02203   }
02204   rc = CryptAcquireContext(&hProv, containerName, providerName, 
02205                            PROV_RSA_FULL, CRYPT_NEWKEYSET);
02206   if (!rc) {
02207     msError = GetLastError();
02208     *pError = CKR_DEVICE_ERROR;
02209     goto loser;
02210   }
02211 
02212   *pError = ckcapi_buildPrivateKeyBlob(
02213               &keyBlob, 
02214               &modulus, 
02215               &publicExponent, 
02216               &privateExponent,
02217               &prime1,
02218               &prime2, 
02219               &exponent1, 
02220               &exponent2, 
02221               &coefficient, 
02222               decrypt);
02223   if (CKR_OK != *pError) {
02224     goto loser;
02225   }
02226 
02227   rc = CryptImportKey(hProv, keyBlob.data, keyBlob.size, 
02228                     0, CRYPT_EXPORTABLE, &hKey);
02229   if (!rc) {
02230     msError = GetLastError();
02231     *pError = CKR_DEVICE_ERROR;
02232     goto loser;
02233   }
02234 
02235   idData = nss_ZNEWARRAY(NULL, char, keyID.size);
02236   if ((void *)NULL == idData) {
02237     *pError = CKR_HOST_MEMORY;
02238     goto loser;
02239   }
02240   nsslibc_memcpy(idData, keyID.data, keyID.size);
02241 
02242   provInfo.pwszContainerName = nss_ckcapi_UTF8ToWide(containerName);
02243   provInfo.pwszProvName = nss_ckcapi_UTF8ToWide(providerName);
02244   provInfo.dwProvType = PROV_RSA_FULL;
02245   provInfo.dwFlags = 0;
02246   provInfo.cProvParam = 0;
02247   provInfo.rgProvParam = NULL;
02248   provInfo.dwKeySpec = keySpec;
02249 
02250   msKeyID.cbData = keyID.size;
02251   msKeyID.pbData = keyID.data;
02252 
02253   rc = CryptSetKeyIdentifierProperty(&msKeyID, CERT_KEY_PROV_INFO_PROP_ID,
02254                                      0, NULL, NULL, &provInfo);
02255   if (!rc) {
02256     goto loser;
02257   }
02258 
02259   /* handle error here */
02260   io = nss_ZNEW(NULL, ckcapiInternalObject);
02261   if ((ckcapiInternalObject *)NULL == io) {
02262     *pError = CKR_HOST_MEMORY;
02263     goto loser;
02264   }
02265   io->type = ckcapiBareKey;
02266   io->objClass = CKO_PRIVATE_KEY;
02267   io->u.key.provInfo = provInfo;
02268   io->u.key.provName = providerName;
02269   io->u.key.containerName = containerName;
02270   io->u.key.hProv = hProv; /* save the handle */
02271   io->idData = idData;
02272   io->id.data = idData;
02273   io->id.size = keyID.size;
02274   /* done with the key handle */
02275   CryptDestroyKey(hKey);
02276   return io;
02277 
02278 loser:
02279   nss_ZFreeIf(containerName);
02280   nss_ZFreeIf(providerName);
02281   nss_ZFreeIf(idData);
02282   if (0 != hProv) {
02283     CryptReleaseContext(hProv, 0);
02284   }
02285   if (0 != hKey) {
02286     CryptDestroyKey(hKey);
02287   }
02288   return (ckcapiInternalObject *)NULL;
02289 }
02290 
02291 
02292 NSS_EXTERN NSSCKMDObject *
02293 nss_ckcapi_CreateObject
02294 (
02295   NSSCKFWSession *fwSession,
02296   CK_ATTRIBUTE_PTR pTemplate,
02297   CK_ULONG ulAttributeCount,
02298   CK_RV *pError
02299 )
02300 {
02301   CK_OBJECT_CLASS objClass;
02302   ckcapiInternalObject *io;
02303   CK_BBOOL isToken;
02304 
02305   /*
02306    * only create token objects
02307    */
02308   isToken = nss_ckcapi_GetBoolAttribute(CKA_TOKEN, pTemplate, 
02309                                    ulAttributeCount, pError);
02310   if (CKR_OK != *pError) {
02311     return (NSSCKMDObject *) NULL;
02312   }
02313   if (!isToken) {
02314     *pError = CKR_ATTRIBUTE_VALUE_INVALID;
02315     return (NSSCKMDObject *) NULL;
02316   }
02317 
02318   /*
02319    * only create keys and certs.
02320    */
02321   objClass = nss_ckcapi_GetULongAttribute(CKA_CLASS, pTemplate, 
02322                                      ulAttributeCount, pError);
02323   if (CKR_OK != *pError) {
02324     return (NSSCKMDObject *) NULL;
02325   }
02326 #ifdef notdef
02327   if (objClass == CKO_PUBLIC_KEY) {
02328     return CKR_OK; /* fake public key creation, happens as a side effect of
02329                     * private key creation */
02330   }
02331 #endif
02332   if (objClass == CKO_CERTIFICATE) {
02333     io = nss_ckcapi_CreateCertificate(fwSession, pTemplate, 
02334                                   ulAttributeCount, pError);
02335   } else if (objClass == CKO_PRIVATE_KEY) {
02336     io = nss_ckcapi_CreatePrivateKey(fwSession, pTemplate, 
02337                                      ulAttributeCount, pError);
02338   } else {
02339     *pError = CKR_ATTRIBUTE_VALUE_INVALID;
02340   }
02341 
02342   if ((ckcapiInternalObject *)NULL == io) {
02343     return (NSSCKMDObject *) NULL;
02344   }
02345   return nss_ckcapi_CreateMDObject(NULL, io, pError);
02346 }