cmspubkey.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. /*
  5. * CMS public key crypto
  6. */
  7. #include "cmslocal.h"
  8. #include "cert.h"
  9. #include "keyhi.h"
  10. #include "secasn1.h"
  11. #include "secitem.h"
  12. #include "secoid.h"
  13. #include "pk11func.h"
  14. #include "secerr.h"
  15. /* ====== RSA ======================================================================= */
  16. /*
  17. * NSS_CMSUtil_EncryptSymKey_RSA - wrap a symmetric key with RSA
  18. *
  19. * this function takes a symmetric key and encrypts it using an RSA public key
  20. * according to PKCS#1 and RFC2633 (S/MIME)
  21. */
  22. SECStatus
  23. NSS_CMSUtil_EncryptSymKey_RSA(PLArenaPool *poolp, CERTCertificate *cert,
  24. PK11SymKey *bulkkey,
  25. SECItem *encKey)
  26. {
  27. SECStatus rv;
  28. SECKEYPublicKey *publickey;
  29. publickey = CERT_ExtractPublicKey(cert);
  30. if (publickey == NULL)
  31. return SECFailure;
  32. rv = NSS_CMSUtil_EncryptSymKey_RSAPubKey(poolp, publickey, bulkkey, encKey);
  33. SECKEY_DestroyPublicKey(publickey);
  34. return rv;
  35. }
  36. SECStatus
  37. NSS_CMSUtil_EncryptSymKey_RSAPubKey(PLArenaPool *poolp,
  38. SECKEYPublicKey *publickey,
  39. PK11SymKey *bulkkey, SECItem *encKey)
  40. {
  41. SECStatus rv;
  42. int data_len;
  43. KeyType keyType;
  44. void *mark = NULL;
  45. mark = PORT_ArenaMark(poolp);
  46. if (!mark)
  47. goto loser;
  48. /* sanity check */
  49. keyType = SECKEY_GetPublicKeyType(publickey);
  50. PORT_Assert(keyType == rsaKey);
  51. if (keyType != rsaKey) {
  52. goto loser;
  53. }
  54. /* allocate memory for the encrypted key */
  55. data_len = SECKEY_PublicKeyStrength(publickey); /* block size (assumed to be > keylen) */
  56. encKey->data = (unsigned char *)PORT_ArenaAlloc(poolp, data_len);
  57. encKey->len = data_len;
  58. if (encKey->data == NULL)
  59. goto loser;
  60. /* encrypt the key now */
  61. rv = PK11_PubWrapSymKey(PK11_AlgtagToMechanism(SEC_OID_PKCS1_RSA_ENCRYPTION),
  62. publickey, bulkkey, encKey);
  63. if (rv != SECSuccess)
  64. goto loser;
  65. PORT_ArenaUnmark(poolp, mark);
  66. return SECSuccess;
  67. loser:
  68. if (mark) {
  69. PORT_ArenaRelease(poolp, mark);
  70. }
  71. return SECFailure;
  72. }
  73. /*
  74. * NSS_CMSUtil_DecryptSymKey_RSA - unwrap a RSA-wrapped symmetric key
  75. *
  76. * this function takes an RSA-wrapped symmetric key and unwraps it, returning a symmetric
  77. * key handle. Please note that the actual unwrapped key data may not be allowed to leave
  78. * a hardware token...
  79. */
  80. PK11SymKey *
  81. NSS_CMSUtil_DecryptSymKey_RSA(SECKEYPrivateKey *privkey, SECItem *encKey, SECOidTag bulkalgtag)
  82. {
  83. /* that's easy */
  84. CK_MECHANISM_TYPE target;
  85. PORT_Assert(bulkalgtag != SEC_OID_UNKNOWN);
  86. target = PK11_AlgtagToMechanism(bulkalgtag);
  87. if (bulkalgtag == SEC_OID_UNKNOWN || target == CKM_INVALID_MECHANISM) {
  88. PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
  89. return NULL;
  90. }
  91. return PK11_PubUnwrapSymKey(privkey, encKey, target, CKA_DECRYPT, 0);
  92. }
  93. /* ====== ESDH (Ephemeral-Static Diffie-Hellman) ==================================== */
  94. SECStatus
  95. NSS_CMSUtil_EncryptSymKey_ESDH(PLArenaPool *poolp, CERTCertificate *cert, PK11SymKey *key,
  96. SECItem *encKey, SECItem **ukm, SECAlgorithmID *keyEncAlg,
  97. SECItem *pubKey)
  98. {
  99. #if 0 /* not yet done */
  100. SECOidTag certalgtag; /* the certificate's encryption algorithm */
  101. SECOidTag encalgtag; /* the algorithm used for key exchange/agreement */
  102. SECStatus rv;
  103. SECItem *params = NULL;
  104. int data_len;
  105. SECStatus err;
  106. PK11SymKey *tek;
  107. CERTCertificate *ourCert;
  108. SECKEYPublicKey *ourPubKey;
  109. NSSCMSKEATemplateSelector whichKEA = NSSCMSKEAInvalid;
  110. certalgtag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));
  111. PORT_Assert(certalgtag == SEC_OID_X942_DIFFIE_HELMAN_KEY);
  112. /* We really want to show our KEA tag as the key exchange algorithm tag. */
  113. encalgtag = SEC_OID_CMS_EPHEMERAL_STATIC_DIFFIE_HELLMAN;
  114. /* Get the public key of the recipient. */
  115. publickey = CERT_ExtractPublicKey(cert);
  116. if (publickey == NULL) goto loser;
  117. /* XXXX generate a DH key pair on a PKCS11 module (XXX which parameters?) */
  118. /* XXXX */ourCert = PK11_FindBestKEAMatch(cert, wincx);
  119. if (ourCert == NULL) goto loser;
  120. arena = PORT_NewArena(1024);
  121. if (arena == NULL) goto loser;
  122. /* While we're here, extract the key pair's public key data and copy it into */
  123. /* the outgoing parameters. */
  124. /* XXXX */ourPubKey = CERT_ExtractPublicKey(ourCert);
  125. if (ourPubKey == NULL)
  126. {
  127. goto loser;
  128. }
  129. SECITEM_CopyItem(arena, pubKey, /* XXX */&(ourPubKey->u.fortezza.KEAKey));
  130. SECKEY_DestroyPublicKey(ourPubKey); /* we only need the private key from now on */
  131. ourPubKey = NULL;
  132. /* Extract our private key in order to derive the KEA key. */
  133. ourPrivKey = PK11_FindKeyByAnyCert(ourCert,wincx);
  134. CERT_DestroyCertificate(ourCert); /* we're done with this */
  135. if (!ourPrivKey) goto loser;
  136. /* If ukm desired, prepare it - allocate enough space (filled with zeros). */
  137. if (ukm) {
  138. ukm->data = (unsigned char*)PORT_ArenaZAlloc(arena,/* XXXX */);
  139. ukm->len = /* XXXX */;
  140. }
  141. /* Generate the KEK (key exchange key) according to RFC2631 which we use
  142. * to wrap the bulk encryption key. */
  143. kek = PK11_PubDerive(ourPrivKey, publickey, PR_TRUE,
  144. ukm, NULL,
  145. /* XXXX */CKM_KEA_KEY_DERIVE, /* XXXX */CKM_SKIPJACK_WRAP,
  146. CKA_WRAP, 0, wincx);
  147. SECKEY_DestroyPublicKey(publickey);
  148. SECKEY_DestroyPrivateKey(ourPrivKey);
  149. publickey = NULL;
  150. ourPrivKey = NULL;
  151. if (!kek)
  152. goto loser;
  153. /* allocate space for the encrypted CEK (bulk key) */
  154. encKey->data = (unsigned char*)PORT_ArenaAlloc(poolp, SMIME_FORTEZZA_MAX_KEY_SIZE);
  155. encKey->len = SMIME_FORTEZZA_MAX_KEY_SIZE;
  156. if (encKey->data == NULL)
  157. {
  158. PK11_FreeSymKey(kek);
  159. goto loser;
  160. }
  161. /* Wrap the bulk key using CMSRC2WRAP or CMS3DESWRAP, depending on the */
  162. /* bulk encryption algorithm */
  163. switch (/* XXXX */PK11_AlgtagToMechanism(enccinfo->encalg))
  164. {
  165. case /* XXXX */CKM_SKIPJACK_CFB8:
  166. err = PK11_WrapSymKey(/* XXXX */CKM_CMS3DES_WRAP, NULL, kek, bulkkey, encKey);
  167. whichKEA = NSSCMSKEAUsesSkipjack;
  168. break;
  169. case /* XXXX */CKM_SKIPJACK_CFB8:
  170. err = PK11_WrapSymKey(/* XXXX */CKM_CMSRC2_WRAP, NULL, kek, bulkkey, encKey);
  171. whichKEA = NSSCMSKEAUsesSkipjack;
  172. break;
  173. default:
  174. /* XXXX what do we do here? Neither RC2 nor 3DES... */
  175. err = SECFailure;
  176. /* set error */
  177. break;
  178. }
  179. PK11_FreeSymKey(kek); /* we do not need the KEK anymore */
  180. if (err != SECSuccess)
  181. goto loser;
  182. PORT_Assert(whichKEA != NSSCMSKEAInvalid);
  183. /* see RFC2630 12.3.1.1 "keyEncryptionAlgorithm must be ..." */
  184. /* params is the DER encoded key wrap algorithm (with parameters!) (XXX) */
  185. params = SEC_ASN1EncodeItem(arena, NULL, &keaParams, sec_pkcs7_get_kea_template(whichKEA));
  186. if (params == NULL)
  187. goto loser;
  188. /* now set keyEncAlg */
  189. rv = SECOID_SetAlgorithmID(poolp, keyEncAlg, SEC_OID_CMS_EPHEMERAL_STATIC_DIFFIE_HELLMAN, params);
  190. if (rv != SECSuccess)
  191. goto loser;
  192. /* XXXXXXX this is not right yet */
  193. loser:
  194. if (arena) {
  195. PORT_FreeArena(arena, PR_FALSE);
  196. }
  197. if (publickey) {
  198. SECKEY_DestroyPublicKey(publickey);
  199. }
  200. if (ourPrivKey) {
  201. SECKEY_DestroyPrivateKey(ourPrivKey);
  202. }
  203. #endif
  204. return SECFailure;
  205. }
  206. PK11SymKey *
  207. NSS_CMSUtil_DecryptSymKey_ESDH(SECKEYPrivateKey *privkey, SECItem *encKey,
  208. SECAlgorithmID *keyEncAlg, SECOidTag bulkalgtag,
  209. void *pwfn_arg)
  210. {
  211. #if 0 /* not yet done */
  212. SECStatus err;
  213. CK_MECHANISM_TYPE bulkType;
  214. PK11SymKey *tek;
  215. SECKEYPublicKey *originatorPubKey;
  216. NSSCMSSMIMEKEAParameters keaParams;
  217. /* XXXX get originator's public key */
  218. originatorPubKey = PK11_MakeKEAPubKey(keaParams.originatorKEAKey.data,
  219. keaParams.originatorKEAKey.len);
  220. if (originatorPubKey == NULL)
  221. goto loser;
  222. /* Generate the TEK (token exchange key) which we use to unwrap the bulk encryption key.
  223. The Derive function generates a shared secret and combines it with the originatorRA
  224. data to come up with an unique session key */
  225. tek = PK11_PubDerive(privkey, originatorPubKey, PR_FALSE,
  226. &keaParams.originatorRA, NULL,
  227. CKM_KEA_KEY_DERIVE, CKM_SKIPJACK_WRAP,
  228. CKA_WRAP, 0, pwfn_arg);
  229. SECKEY_DestroyPublicKey(originatorPubKey); /* not needed anymore */
  230. if (tek == NULL)
  231. goto loser;
  232. /* Now that we have the TEK, unwrap the bulk key
  233. with which to decrypt the message. */
  234. /* Skipjack is being used as the bulk encryption algorithm.*/
  235. /* Unwrap the bulk key. */
  236. bulkkey = PK11_UnwrapSymKey(tek, CKM_SKIPJACK_WRAP, NULL,
  237. encKey, CKM_SKIPJACK_CBC64, CKA_DECRYPT, 0);
  238. return bulkkey;
  239. loser:
  240. #endif
  241. return NULL;
  242. }