cmssiginfo.c 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082
  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 signerInfo methods.
  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 "prtime.h"
  15. #include "secerr.h"
  16. #include "secder.h"
  17. #include "cryptohi.h"
  18. #include "smime.h"
  19. /* =============================================================================
  20. * SIGNERINFO
  21. */
  22. NSSCMSSignerInfo *
  23. nss_cmssignerinfo_create(NSSCMSMessage *cmsg, NSSCMSSignerIDSelector type,
  24. CERTCertificate *cert, SECItem *subjKeyID, SECKEYPublicKey *pubKey,
  25. SECKEYPrivateKey *signingKey, SECOidTag digestalgtag);
  26. NSSCMSSignerInfo *
  27. NSS_CMSSignerInfo_CreateWithSubjKeyID(NSSCMSMessage *cmsg, SECItem *subjKeyID,
  28. SECKEYPublicKey *pubKey,
  29. SECKEYPrivateKey *signingKey, SECOidTag digestalgtag)
  30. {
  31. return nss_cmssignerinfo_create(cmsg, NSSCMSSignerID_SubjectKeyID, NULL,
  32. subjKeyID, pubKey, signingKey, digestalgtag);
  33. }
  34. NSSCMSSignerInfo *
  35. NSS_CMSSignerInfo_Create(NSSCMSMessage *cmsg, CERTCertificate *cert, SECOidTag digestalgtag)
  36. {
  37. return nss_cmssignerinfo_create(cmsg, NSSCMSSignerID_IssuerSN, cert, NULL,
  38. NULL, NULL, digestalgtag);
  39. }
  40. NSSCMSSignerInfo *
  41. nss_cmssignerinfo_create(NSSCMSMessage *cmsg, NSSCMSSignerIDSelector type,
  42. CERTCertificate *cert, SECItem *subjKeyID, SECKEYPublicKey *pubKey,
  43. SECKEYPrivateKey *signingKey, SECOidTag digestalgtag)
  44. {
  45. void *mark;
  46. NSSCMSSignerInfo *signerinfo;
  47. int version;
  48. PLArenaPool *poolp;
  49. SECStatus rv;
  50. poolp = cmsg->poolp;
  51. mark = PORT_ArenaMark(poolp);
  52. signerinfo = (NSSCMSSignerInfo *)PORT_ArenaZAlloc(poolp, sizeof(NSSCMSSignerInfo));
  53. if (signerinfo == NULL) {
  54. PORT_ArenaRelease(poolp, mark);
  55. return NULL;
  56. }
  57. signerinfo->cmsg = cmsg;
  58. switch (type) {
  59. case NSSCMSSignerID_IssuerSN:
  60. signerinfo->signerIdentifier.identifierType = NSSCMSSignerID_IssuerSN;
  61. if ((signerinfo->cert = CERT_DupCertificate(cert)) == NULL)
  62. goto loser;
  63. if ((signerinfo->signerIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL)
  64. goto loser;
  65. break;
  66. case NSSCMSSignerID_SubjectKeyID:
  67. signerinfo->signerIdentifier.identifierType = NSSCMSSignerID_SubjectKeyID;
  68. PORT_Assert(subjKeyID);
  69. if (!subjKeyID)
  70. goto loser;
  71. signerinfo->signerIdentifier.id.subjectKeyID = PORT_ArenaNew(poolp, SECItem);
  72. rv = SECITEM_CopyItem(poolp, signerinfo->signerIdentifier.id.subjectKeyID,
  73. subjKeyID);
  74. if (rv != SECSuccess) {
  75. goto loser;
  76. }
  77. signerinfo->signingKey = SECKEY_CopyPrivateKey(signingKey);
  78. if (!signerinfo->signingKey)
  79. goto loser;
  80. signerinfo->pubKey = SECKEY_CopyPublicKey(pubKey);
  81. if (!signerinfo->pubKey)
  82. goto loser;
  83. break;
  84. default:
  85. goto loser;
  86. }
  87. /* set version right now */
  88. version = NSS_CMS_SIGNER_INFO_VERSION_ISSUERSN;
  89. /* RFC2630 5.3 "version is the syntax version number. If the .... " */
  90. if (signerinfo->signerIdentifier.identifierType == NSSCMSSignerID_SubjectKeyID)
  91. version = NSS_CMS_SIGNER_INFO_VERSION_SUBJKEY;
  92. (void)SEC_ASN1EncodeInteger(poolp, &(signerinfo->version), (long)version);
  93. if (SECOID_SetAlgorithmID(poolp, &signerinfo->digestAlg, digestalgtag, NULL) != SECSuccess)
  94. goto loser;
  95. PORT_ArenaUnmark(poolp, mark);
  96. return signerinfo;
  97. loser:
  98. PORT_ArenaRelease(poolp, mark);
  99. return NULL;
  100. }
  101. /*
  102. * NSS_CMSSignerInfo_Destroy - destroy a SignerInfo data structure
  103. */
  104. void
  105. NSS_CMSSignerInfo_Destroy(NSSCMSSignerInfo *si)
  106. {
  107. if (si->cert != NULL)
  108. CERT_DestroyCertificate(si->cert);
  109. if (si->certList != NULL)
  110. CERT_DestroyCertificateList(si->certList);
  111. /* XXX storage ??? */
  112. }
  113. static SECOidTag
  114. NSS_CMSSignerInfo_GetSignatureAlgorithmOidTag(KeyType keyType,
  115. SECOidTag pubkAlgTag,
  116. SECOidTag signAlgTag)
  117. {
  118. switch (keyType) {
  119. case rsaKey:
  120. return pubkAlgTag;
  121. case rsaPssKey:
  122. case dsaKey:
  123. case ecKey:
  124. return signAlgTag;
  125. default:
  126. return SEC_OID_UNKNOWN;
  127. }
  128. }
  129. /*
  130. * NSS_CMSSignerInfo_Sign - sign something
  131. *
  132. */
  133. SECStatus
  134. NSS_CMSSignerInfo_Sign(NSSCMSSignerInfo *signerinfo, SECItem *digest,
  135. SECItem *contentType)
  136. {
  137. CERTCertificate *cert;
  138. SECKEYPrivateKey *privkey = NULL;
  139. SECOidTag digestalgtag;
  140. SECOidTag pubkAlgTag;
  141. SECOidTag signAlgTag;
  142. SECOidTag cmsSignAlgTag;
  143. SECItem signature = { 0 };
  144. SECStatus rv;
  145. PLArenaPool *poolp, *tmppoolp = NULL;
  146. SECAlgorithmID *algID, freeAlgID;
  147. CERTSubjectPublicKeyInfo *spki;
  148. PORT_Assert(digest != NULL);
  149. poolp = signerinfo->cmsg->poolp;
  150. switch (signerinfo->signerIdentifier.identifierType) {
  151. case NSSCMSSignerID_IssuerSN:
  152. cert = signerinfo->cert;
  153. privkey = PK11_FindKeyByAnyCert(cert, signerinfo->cmsg->pwfn_arg);
  154. if (privkey == NULL)
  155. goto loser;
  156. algID = &cert->subjectPublicKeyInfo.algorithm;
  157. break;
  158. case NSSCMSSignerID_SubjectKeyID:
  159. privkey = signerinfo->signingKey;
  160. signerinfo->signingKey = NULL;
  161. spki = SECKEY_CreateSubjectPublicKeyInfo(signerinfo->pubKey);
  162. SECKEY_DestroyPublicKey(signerinfo->pubKey);
  163. signerinfo->pubKey = NULL;
  164. SECOID_CopyAlgorithmID(NULL, &freeAlgID, &spki->algorithm);
  165. SECKEY_DestroySubjectPublicKeyInfo(spki);
  166. algID = &freeAlgID;
  167. break;
  168. default:
  169. goto loser;
  170. }
  171. digestalgtag = NSS_CMSSignerInfo_GetDigestAlgTag(signerinfo);
  172. /*
  173. * XXX I think there should be a cert-level interface for this,
  174. * so that I do not have to know about subjectPublicKeyInfo...
  175. */
  176. pubkAlgTag = SECOID_GetAlgorithmTag(algID);
  177. if (algID == &freeAlgID) {
  178. SECOID_DestroyAlgorithmID(&freeAlgID, PR_FALSE);
  179. }
  180. signAlgTag = SEC_GetSignatureAlgorithmOidTag(SECKEY_GetPrivateKeyType(privkey),
  181. digestalgtag);
  182. if (signAlgTag == SEC_OID_UNKNOWN) {
  183. PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
  184. goto loser;
  185. }
  186. cmsSignAlgTag = NSS_CMSSignerInfo_GetSignatureAlgorithmOidTag(
  187. SECKEY_GetPrivateKeyType(privkey), pubkAlgTag, signAlgTag);
  188. if (cmsSignAlgTag == SEC_OID_UNKNOWN) {
  189. PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
  190. goto loser;
  191. }
  192. if (SECOID_SetAlgorithmID(poolp, &(signerinfo->digestEncAlg),
  193. cmsSignAlgTag, NULL) != SECSuccess)
  194. goto loser;
  195. if (signerinfo->authAttr != NULL) {
  196. SECItem encoded_attrs;
  197. /* find and fill in the message digest attribute. */
  198. rv = NSS_CMSAttributeArray_SetAttr(poolp, &(signerinfo->authAttr),
  199. SEC_OID_PKCS9_MESSAGE_DIGEST, digest, PR_FALSE);
  200. if (rv != SECSuccess)
  201. goto loser;
  202. if (contentType != NULL) {
  203. /* if the caller wants us to, find and fill in the content type attribute. */
  204. rv = NSS_CMSAttributeArray_SetAttr(poolp, &(signerinfo->authAttr),
  205. SEC_OID_PKCS9_CONTENT_TYPE, contentType, PR_FALSE);
  206. if (rv != SECSuccess)
  207. goto loser;
  208. }
  209. if ((tmppoolp = PORT_NewArena(1024)) == NULL) {
  210. PORT_SetError(SEC_ERROR_NO_MEMORY);
  211. goto loser;
  212. }
  213. /*
  214. * Before encoding, reorder the attributes so that when they
  215. * are encoded, they will be conforming DER, which is required
  216. * to have a specific order and that is what must be used for
  217. * the hash/signature. We do this here, rather than building
  218. * it into EncodeAttributes, because we do not want to do
  219. * such reordering on incoming messages (which also uses
  220. * EncodeAttributes) or our old signatures (and other "broken"
  221. * implementations) will not verify. So, we want to guarantee
  222. * that we send out good DER encodings of attributes, but not
  223. * to expect to receive them.
  224. */
  225. if (NSS_CMSAttributeArray_Reorder(signerinfo->authAttr) != SECSuccess)
  226. goto loser;
  227. encoded_attrs.data = NULL;
  228. encoded_attrs.len = 0;
  229. if (NSS_CMSAttributeArray_Encode(tmppoolp, &(signerinfo->authAttr),
  230. &encoded_attrs) == NULL)
  231. goto loser;
  232. rv = SEC_SignData(&signature, encoded_attrs.data, encoded_attrs.len,
  233. privkey, signAlgTag);
  234. PORT_FreeArena(tmppoolp, PR_FALSE); /* awkward memory management :-( */
  235. tmppoolp = 0;
  236. } else {
  237. rv = SGN_Digest(privkey, digestalgtag, &signature, digest);
  238. }
  239. SECKEY_DestroyPrivateKey(privkey);
  240. privkey = NULL;
  241. if (rv != SECSuccess)
  242. goto loser;
  243. if (SECITEM_CopyItem(poolp, &(signerinfo->encDigest), &signature) != SECSuccess)
  244. goto loser;
  245. SECITEM_FreeItem(&signature, PR_FALSE);
  246. return SECSuccess;
  247. loser:
  248. if (signature.len != 0)
  249. SECITEM_FreeItem(&signature, PR_FALSE);
  250. if (privkey)
  251. SECKEY_DestroyPrivateKey(privkey);
  252. if (tmppoolp)
  253. PORT_FreeArena(tmppoolp, PR_FALSE);
  254. return SECFailure;
  255. }
  256. SECStatus
  257. NSS_CMSSignerInfo_VerifyCertificate(NSSCMSSignerInfo *signerinfo, CERTCertDBHandle *certdb,
  258. SECCertUsage certusage)
  259. {
  260. CERTCertificate *cert;
  261. PRTime stime;
  262. if ((cert = NSS_CMSSignerInfo_GetSigningCertificate(signerinfo, certdb)) == NULL) {
  263. signerinfo->verificationStatus = NSSCMSVS_SigningCertNotFound;
  264. return SECFailure;
  265. }
  266. /*
  267. * Get and convert the signing time; if available, it will be used
  268. * both on the cert verification and for importing the sender
  269. * email profile.
  270. */
  271. if (NSS_CMSSignerInfo_GetSigningTime(signerinfo, &stime) != SECSuccess)
  272. stime = PR_Now(); /* not found or conversion failed, so check against now */
  273. /*
  274. * XXX This uses the signing time, if available. Additionally, we
  275. * might want to, if there is no signing time, get the message time
  276. * from the mail header itself, and use that. That would require
  277. * a change to our interface though, and for S/MIME callers to pass
  278. * in a time (and for non-S/MIME callers to pass in nothing, or
  279. * maybe make them pass in the current time, always?).
  280. */
  281. if (CERT_VerifyCert(certdb, cert, PR_TRUE, certusage, stime,
  282. signerinfo->cmsg->pwfn_arg, NULL) != SECSuccess) {
  283. signerinfo->verificationStatus = NSSCMSVS_SigningCertNotTrusted;
  284. return SECFailure;
  285. }
  286. return SECSuccess;
  287. }
  288. /*
  289. * NSS_CMSSignerInfo_Verify - verify the signature of a single SignerInfo
  290. *
  291. * Just verifies the signature. The assumption is that verification of
  292. * the certificate is done already.
  293. */
  294. SECStatus
  295. NSS_CMSSignerInfo_Verify(NSSCMSSignerInfo *signerinfo,
  296. SECItem *digest, /* may be NULL */
  297. SECItem *contentType) /* may be NULL */
  298. {
  299. SECKEYPublicKey *publickey = NULL;
  300. NSSCMSAttribute *attr;
  301. SECItem encoded_attrs;
  302. CERTCertificate *cert;
  303. NSSCMSVerificationStatus vs = NSSCMSVS_Unverified;
  304. PLArenaPool *poolp;
  305. SECOidTag digestalgtag;
  306. SECOidTag pubkAlgTag;
  307. SECOidTag digestalgtagCmp;
  308. SECOidTag sigAlgTag;
  309. if (signerinfo == NULL)
  310. return SECFailure;
  311. /* NSS_CMSSignerInfo_GetSigningCertificate will fail if 2nd parm is NULL
  312. ** and cert has not been verified
  313. */
  314. cert = NSS_CMSSignerInfo_GetSigningCertificate(signerinfo, NULL);
  315. if (cert == NULL) {
  316. vs = NSSCMSVS_SigningCertNotFound;
  317. goto loser;
  318. }
  319. if ((publickey = CERT_ExtractPublicKey(cert)) == NULL) {
  320. vs = NSSCMSVS_ProcessingError;
  321. goto loser;
  322. }
  323. digestalgtag = NSS_CMSSignerInfo_GetDigestAlgTag(signerinfo);
  324. pubkAlgTag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));
  325. sigAlgTag = SECOID_GetAlgorithmTag(&(signerinfo->digestEncAlg));
  326. if ((pubkAlgTag == SEC_OID_UNKNOWN) || (digestalgtag == SEC_OID_UNKNOWN) ||
  327. (sigAlgTag == SEC_OID_UNKNOWN)) {
  328. vs = NSSCMSVS_SignatureAlgorithmUnknown;
  329. goto loser;
  330. }
  331. if (!NSS_CMSArray_IsEmpty((void **)signerinfo->authAttr)) {
  332. if (contentType) {
  333. /*
  334. * Check content type
  335. *
  336. * RFC2630 sez that if there are any authenticated attributes,
  337. * then there must be one for content type which matches the
  338. * content type of the content being signed, and there must
  339. * be one for message digest which matches our message digest.
  340. * So check these things first.
  341. */
  342. attr = NSS_CMSAttributeArray_FindAttrByOidTag(signerinfo->authAttr,
  343. SEC_OID_PKCS9_CONTENT_TYPE, PR_TRUE);
  344. if (attr == NULL) {
  345. vs = NSSCMSVS_MalformedSignature;
  346. goto loser;
  347. }
  348. if (NSS_CMSAttribute_CompareValue(attr, contentType) == PR_FALSE) {
  349. vs = NSSCMSVS_MalformedSignature;
  350. goto loser;
  351. }
  352. }
  353. /*
  354. * Check digest
  355. */
  356. attr = NSS_CMSAttributeArray_FindAttrByOidTag(signerinfo->authAttr,
  357. SEC_OID_PKCS9_MESSAGE_DIGEST, PR_TRUE);
  358. if (attr == NULL) {
  359. vs = NSSCMSVS_MalformedSignature;
  360. goto loser;
  361. }
  362. if (!digest ||
  363. NSS_CMSAttribute_CompareValue(attr, digest) == PR_FALSE) {
  364. vs = NSSCMSVS_DigestMismatch;
  365. goto loser;
  366. }
  367. if ((poolp = PORT_NewArena(1024)) == NULL) {
  368. vs = NSSCMSVS_ProcessingError;
  369. goto loser;
  370. }
  371. /*
  372. * Check signature
  373. *
  374. * The signature is based on a digest of the DER-encoded authenticated
  375. * attributes. So, first we encode and then we digest/verify.
  376. * we trust the decoder to have the attributes in the right (sorted)
  377. * order
  378. */
  379. encoded_attrs.data = NULL;
  380. encoded_attrs.len = 0;
  381. if (NSS_CMSAttributeArray_Encode(poolp, &(signerinfo->authAttr),
  382. &encoded_attrs) == NULL ||
  383. encoded_attrs.data == NULL || encoded_attrs.len == 0) {
  384. PORT_FreeArena(poolp, PR_FALSE);
  385. vs = NSSCMSVS_ProcessingError;
  386. goto loser;
  387. }
  388. if (sigAlgTag == pubkAlgTag) {
  389. /* This is to handle cases in which signatureAlgorithm field
  390. * specifies the public key algorithm rather than a signature
  391. * algorithm. */
  392. vs = (VFY_VerifyDataDirect(encoded_attrs.data, encoded_attrs.len,
  393. publickey, &(signerinfo->encDigest), pubkAlgTag,
  394. digestalgtag, NULL, signerinfo->cmsg->pwfn_arg) != SECSuccess)
  395. ? NSSCMSVS_BadSignature
  396. : NSSCMSVS_GoodSignature;
  397. } else {
  398. if (VFY_VerifyDataWithAlgorithmID(encoded_attrs.data,
  399. encoded_attrs.len, publickey, &(signerinfo->encDigest),
  400. &(signerinfo->digestEncAlg), &digestalgtagCmp,
  401. signerinfo->cmsg->pwfn_arg) != SECSuccess) {
  402. vs = NSSCMSVS_BadSignature;
  403. } else if (digestalgtagCmp != digestalgtag) {
  404. PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
  405. vs = NSSCMSVS_BadSignature;
  406. } else {
  407. vs = NSSCMSVS_GoodSignature;
  408. }
  409. }
  410. PORT_FreeArena(poolp, PR_FALSE); /* awkward memory management :-( */
  411. } else {
  412. SECItem *sig;
  413. /* No authenticated attributes.
  414. ** The signature is based on the plain message digest.
  415. */
  416. sig = &(signerinfo->encDigest);
  417. if (sig->len == 0)
  418. goto loser;
  419. if (sigAlgTag == pubkAlgTag) {
  420. /* This is to handle cases in which signatureAlgorithm field
  421. * specifies the public key algorithm rather than a signature
  422. * algorithm. */
  423. vs = (!digest ||
  424. VFY_VerifyDigestDirect(digest, publickey, sig, pubkAlgTag,
  425. digestalgtag, signerinfo->cmsg->pwfn_arg) != SECSuccess)
  426. ? NSSCMSVS_BadSignature
  427. : NSSCMSVS_GoodSignature;
  428. } else {
  429. vs = (!digest ||
  430. VFY_VerifyDigestWithAlgorithmID(digest, publickey, sig,
  431. &(signerinfo->digestEncAlg), digestalgtag,
  432. signerinfo->cmsg->pwfn_arg) != SECSuccess)
  433. ? NSSCMSVS_BadSignature
  434. : NSSCMSVS_GoodSignature;
  435. }
  436. }
  437. if (vs == NSSCMSVS_BadSignature) {
  438. int error = PORT_GetError();
  439. /*
  440. * XXX Change the generic error into our specific one, because
  441. * in that case we get a better explanation out of the Security
  442. * Advisor. This is really a bug in the PSM error strings (the
  443. * "generic" error has a lousy/wrong message associated with it
  444. * which assumes the signature verification was done for the
  445. * purposes of checking the issuer signature on a certificate)
  446. * but this is at least an easy workaround and/or in the
  447. * Security Advisor, which specifically checks for the error
  448. * SEC_ERROR_PKCS7_BAD_SIGNATURE and gives more explanation
  449. * in that case but does not similarly check for
  450. * SEC_ERROR_BAD_SIGNATURE. It probably should, but then would
  451. * probably say the wrong thing in the case that it *was* the
  452. * certificate signature check that failed during the cert
  453. * verification done above. Our error handling is really a mess.
  454. */
  455. if (error == SEC_ERROR_BAD_SIGNATURE)
  456. PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
  457. /*
  458. * map algorithm failures to NSSCMSVS values
  459. */
  460. if ((error == SEC_ERROR_PKCS7_KEYALG_MISMATCH) ||
  461. (error == SEC_ERROR_INVALID_ALGORITHM)) {
  462. /* keep the same error code as 3.11 and before */
  463. PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
  464. vs = NSSCMSVS_SignatureAlgorithmUnsupported;
  465. }
  466. }
  467. if (publickey != NULL)
  468. SECKEY_DestroyPublicKey(publickey);
  469. signerinfo->verificationStatus = vs;
  470. return (vs == NSSCMSVS_GoodSignature) ? SECSuccess : SECFailure;
  471. loser:
  472. if (publickey != NULL)
  473. SECKEY_DestroyPublicKey(publickey);
  474. signerinfo->verificationStatus = vs;
  475. PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
  476. return SECFailure;
  477. }
  478. NSSCMSVerificationStatus
  479. NSS_CMSSignerInfo_GetVerificationStatus(NSSCMSSignerInfo *signerinfo)
  480. {
  481. return signerinfo->verificationStatus;
  482. }
  483. SECOidData *
  484. NSS_CMSSignerInfo_GetDigestAlg(NSSCMSSignerInfo *signerinfo)
  485. {
  486. SECOidData *algdata;
  487. SECOidTag algtag;
  488. algdata = SECOID_FindOID(&(signerinfo->digestAlg.algorithm));
  489. if (algdata == NULL) {
  490. return algdata;
  491. }
  492. /* Windows may have given us a signer algorithm oid instead of a digest
  493. * algorithm oid. This call will map to a signer oid to a digest one,
  494. * otherwise it leaves the oid alone and let the chips fall as they may
  495. * if it's not a digest oid.
  496. */
  497. algtag = NSS_CMSUtil_MapSignAlgs(algdata->offset);
  498. if (algtag != algdata->offset) {
  499. /* if the tags don't match, then we must have received a signer
  500. * algorithID. Now we need to get the oid data for the digest
  501. * oid, which the rest of the code is expecting */
  502. algdata = SECOID_FindOIDByTag(algtag);
  503. }
  504. return algdata;
  505. }
  506. SECOidTag
  507. NSS_CMSSignerInfo_GetDigestAlgTag(NSSCMSSignerInfo *signerinfo)
  508. {
  509. SECOidData *algdata;
  510. if (!signerinfo) {
  511. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  512. return SEC_OID_UNKNOWN;
  513. }
  514. algdata = NSS_CMSSignerInfo_GetDigestAlg(signerinfo);
  515. if (algdata != NULL)
  516. return algdata->offset;
  517. else
  518. return SEC_OID_UNKNOWN;
  519. }
  520. CERTCertificateList *
  521. NSS_CMSSignerInfo_GetCertList(NSSCMSSignerInfo *signerinfo)
  522. {
  523. return signerinfo->certList;
  524. }
  525. int
  526. NSS_CMSSignerInfo_GetVersion(NSSCMSSignerInfo *signerinfo)
  527. {
  528. unsigned long version;
  529. /* always take apart the SECItem */
  530. if (SEC_ASN1DecodeInteger(&(signerinfo->version), &version) != SECSuccess)
  531. return 0;
  532. else
  533. return (int)version;
  534. }
  535. /*
  536. * NSS_CMSSignerInfo_GetSigningTime - return the signing time,
  537. * in UTCTime or GeneralizedTime format,
  538. * of a CMS signerInfo.
  539. *
  540. * sinfo - signerInfo data for this signer
  541. *
  542. * Returns a pointer to XXXX (what?)
  543. * A return value of NULL is an error.
  544. */
  545. SECStatus
  546. NSS_CMSSignerInfo_GetSigningTime(NSSCMSSignerInfo *sinfo, PRTime *stime)
  547. {
  548. NSSCMSAttribute *attr;
  549. SECItem *value;
  550. if (sinfo == NULL)
  551. return SECFailure;
  552. if (sinfo->signingTime != 0) {
  553. *stime = sinfo->signingTime; /* cached copy */
  554. return SECSuccess;
  555. }
  556. attr = NSS_CMSAttributeArray_FindAttrByOidTag(sinfo->authAttr,
  557. SEC_OID_PKCS9_SIGNING_TIME, PR_TRUE);
  558. /* XXXX multi-valued attributes NIH */
  559. if (attr == NULL || (value = NSS_CMSAttribute_GetValue(attr)) == NULL)
  560. return SECFailure;
  561. if (DER_DecodeTimeChoice(stime, value) != SECSuccess)
  562. return SECFailure;
  563. sinfo->signingTime = *stime; /* make cached copy */
  564. return SECSuccess;
  565. }
  566. /*
  567. * Return the signing cert of a CMS signerInfo.
  568. *
  569. * the certs in the enclosing SignedData must have been imported already
  570. */
  571. CERTCertificate *
  572. NSS_CMSSignerInfo_GetSigningCertificate(NSSCMSSignerInfo *signerinfo, CERTCertDBHandle *certdb)
  573. {
  574. CERTCertificate *cert;
  575. NSSCMSSignerIdentifier *sid;
  576. if (signerinfo->cert != NULL)
  577. return signerinfo->cert;
  578. /* no certdb, and cert hasn't been set yet? */
  579. if (certdb == NULL)
  580. return NULL;
  581. /*
  582. * This cert will also need to be freed, but since we save it
  583. * in signerinfo for later, we do not want to destroy it when
  584. * we leave this function -- we let the clean-up of the entire
  585. * cinfo structure later do the destroy of this cert.
  586. */
  587. sid = &signerinfo->signerIdentifier;
  588. switch (sid->identifierType) {
  589. case NSSCMSSignerID_IssuerSN:
  590. cert = CERT_FindCertByIssuerAndSN(certdb, sid->id.issuerAndSN);
  591. break;
  592. case NSSCMSSignerID_SubjectKeyID:
  593. cert = CERT_FindCertBySubjectKeyID(certdb, sid->id.subjectKeyID);
  594. break;
  595. default:
  596. cert = NULL;
  597. break;
  598. }
  599. /* cert can be NULL at that point */
  600. signerinfo->cert = cert; /* earmark it */
  601. return cert;
  602. }
  603. /*
  604. * NSS_CMSSignerInfo_GetSignerCommonName - return the common name of the signer
  605. *
  606. * sinfo - signerInfo data for this signer
  607. *
  608. * Returns a pointer to allocated memory, which must be freed with PORT_Free.
  609. * A return value of NULL is an error.
  610. */
  611. char *
  612. NSS_CMSSignerInfo_GetSignerCommonName(NSSCMSSignerInfo *sinfo)
  613. {
  614. CERTCertificate *signercert;
  615. /* will fail if cert is not verified */
  616. if ((signercert = NSS_CMSSignerInfo_GetSigningCertificate(sinfo, NULL)) == NULL)
  617. return NULL;
  618. return (CERT_GetCommonName(&signercert->subject));
  619. }
  620. /*
  621. * NSS_CMSSignerInfo_GetSignerEmailAddress - return the common name of the signer
  622. *
  623. * sinfo - signerInfo data for this signer
  624. *
  625. * Returns a pointer to allocated memory, which must be freed.
  626. * A return value of NULL is an error.
  627. */
  628. char *
  629. NSS_CMSSignerInfo_GetSignerEmailAddress(NSSCMSSignerInfo *sinfo)
  630. {
  631. CERTCertificate *signercert;
  632. if ((signercert = NSS_CMSSignerInfo_GetSigningCertificate(sinfo, NULL)) == NULL)
  633. return NULL;
  634. if (!signercert->emailAddr || !signercert->emailAddr[0])
  635. return NULL;
  636. return (PORT_Strdup(signercert->emailAddr));
  637. }
  638. /*
  639. * NSS_CMSSignerInfo_AddAuthAttr - add an attribute to the
  640. * authenticated (i.e. signed) attributes of "signerinfo".
  641. */
  642. SECStatus
  643. NSS_CMSSignerInfo_AddAuthAttr(NSSCMSSignerInfo *signerinfo, NSSCMSAttribute *attr)
  644. {
  645. return NSS_CMSAttributeArray_AddAttr(signerinfo->cmsg->poolp, &(signerinfo->authAttr), attr);
  646. }
  647. /*
  648. * NSS_CMSSignerInfo_AddUnauthAttr - add an attribute to the
  649. * unauthenticated attributes of "signerinfo".
  650. */
  651. SECStatus
  652. NSS_CMSSignerInfo_AddUnauthAttr(NSSCMSSignerInfo *signerinfo, NSSCMSAttribute *attr)
  653. {
  654. return NSS_CMSAttributeArray_AddAttr(signerinfo->cmsg->poolp, &(signerinfo->unAuthAttr), attr);
  655. }
  656. /*
  657. * NSS_CMSSignerInfo_AddSigningTime - add the signing time to the
  658. * authenticated (i.e. signed) attributes of "signerinfo".
  659. *
  660. * This is expected to be included in outgoing signed
  661. * messages for email (S/MIME) but is likely useful in other situations.
  662. *
  663. * This should only be added once; a second call will do nothing.
  664. *
  665. * XXX This will probably just shove the current time into "signerinfo"
  666. * but it will not actually get signed until the entire item is
  667. * processed for encoding. Is this (expected to be small) delay okay?
  668. */
  669. SECStatus
  670. NSS_CMSSignerInfo_AddSigningTime(NSSCMSSignerInfo *signerinfo, PRTime t)
  671. {
  672. NSSCMSAttribute *attr;
  673. SECItem stime;
  674. void *mark;
  675. PLArenaPool *poolp;
  676. poolp = signerinfo->cmsg->poolp;
  677. mark = PORT_ArenaMark(poolp);
  678. /* create new signing time attribute */
  679. if (DER_EncodeTimeChoice(NULL, &stime, t) != SECSuccess)
  680. goto loser;
  681. if ((attr = NSS_CMSAttribute_Create(poolp, SEC_OID_PKCS9_SIGNING_TIME, &stime, PR_FALSE)) == NULL) {
  682. SECITEM_FreeItem(&stime, PR_FALSE);
  683. goto loser;
  684. }
  685. SECITEM_FreeItem(&stime, PR_FALSE);
  686. if (NSS_CMSSignerInfo_AddAuthAttr(signerinfo, attr) != SECSuccess)
  687. goto loser;
  688. PORT_ArenaUnmark(poolp, mark);
  689. return SECSuccess;
  690. loser:
  691. PORT_ArenaRelease(poolp, mark);
  692. return SECFailure;
  693. }
  694. /*
  695. * NSS_CMSSignerInfo_AddSMIMECaps - add a SMIMECapabilities attribute to the
  696. * authenticated (i.e. signed) attributes of "signerinfo".
  697. *
  698. * This is expected to be included in outgoing signed
  699. * messages for email (S/MIME).
  700. */
  701. SECStatus
  702. NSS_CMSSignerInfo_AddSMIMECaps(NSSCMSSignerInfo *signerinfo)
  703. {
  704. NSSCMSAttribute *attr;
  705. SECItem *smimecaps = NULL;
  706. void *mark;
  707. PLArenaPool *poolp;
  708. poolp = signerinfo->cmsg->poolp;
  709. mark = PORT_ArenaMark(poolp);
  710. smimecaps = SECITEM_AllocItem(poolp, NULL, 0);
  711. if (smimecaps == NULL)
  712. goto loser;
  713. /* create new signing time attribute */
  714. if (NSS_SMIMEUtil_CreateSMIMECapabilities(poolp, smimecaps) != SECSuccess)
  715. goto loser;
  716. if ((attr = NSS_CMSAttribute_Create(poolp, SEC_OID_PKCS9_SMIME_CAPABILITIES, smimecaps, PR_TRUE)) == NULL)
  717. goto loser;
  718. if (NSS_CMSSignerInfo_AddAuthAttr(signerinfo, attr) != SECSuccess)
  719. goto loser;
  720. PORT_ArenaUnmark(poolp, mark);
  721. return SECSuccess;
  722. loser:
  723. PORT_ArenaRelease(poolp, mark);
  724. return SECFailure;
  725. }
  726. /*
  727. * NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs - add a SMIMEEncryptionKeyPreferences attribute to the
  728. * authenticated (i.e. signed) attributes of "signerinfo".
  729. *
  730. * This is expected to be included in outgoing signed messages for email (S/MIME).
  731. */
  732. SECStatus
  733. NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(NSSCMSSignerInfo *signerinfo, CERTCertificate *cert, CERTCertDBHandle *certdb)
  734. {
  735. NSSCMSAttribute *attr;
  736. SECItem *smimeekp = NULL;
  737. void *mark;
  738. PLArenaPool *poolp;
  739. /* verify this cert for encryption */
  740. if (CERT_VerifyCert(certdb, cert, PR_TRUE, certUsageEmailRecipient, PR_Now(), signerinfo->cmsg->pwfn_arg, NULL) != SECSuccess) {
  741. return SECFailure;
  742. }
  743. poolp = signerinfo->cmsg->poolp;
  744. mark = PORT_ArenaMark(poolp);
  745. smimeekp = SECITEM_AllocItem(poolp, NULL, 0);
  746. if (smimeekp == NULL)
  747. goto loser;
  748. /* create new signing time attribute */
  749. if (NSS_SMIMEUtil_CreateSMIMEEncKeyPrefs(poolp, smimeekp, cert) != SECSuccess)
  750. goto loser;
  751. if ((attr = NSS_CMSAttribute_Create(poolp, SEC_OID_SMIME_ENCRYPTION_KEY_PREFERENCE, smimeekp, PR_TRUE)) == NULL)
  752. goto loser;
  753. if (NSS_CMSSignerInfo_AddAuthAttr(signerinfo, attr) != SECSuccess)
  754. goto loser;
  755. PORT_ArenaUnmark(poolp, mark);
  756. return SECSuccess;
  757. loser:
  758. PORT_ArenaRelease(poolp, mark);
  759. return SECFailure;
  760. }
  761. /*
  762. * NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs - add a SMIMEEncryptionKeyPreferences attribute to the
  763. * authenticated (i.e. signed) attributes of "signerinfo", using the OID preferred by Microsoft.
  764. *
  765. * This is expected to be included in outgoing signed messages for email (S/MIME),
  766. * if compatibility with Microsoft mail clients is wanted.
  767. */
  768. SECStatus
  769. NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(NSSCMSSignerInfo *signerinfo, CERTCertificate *cert, CERTCertDBHandle *certdb)
  770. {
  771. NSSCMSAttribute *attr;
  772. SECItem *smimeekp = NULL;
  773. void *mark;
  774. PLArenaPool *poolp;
  775. /* verify this cert for encryption */
  776. if (CERT_VerifyCert(certdb, cert, PR_TRUE, certUsageEmailRecipient, PR_Now(), signerinfo->cmsg->pwfn_arg, NULL) != SECSuccess) {
  777. return SECFailure;
  778. }
  779. poolp = signerinfo->cmsg->poolp;
  780. mark = PORT_ArenaMark(poolp);
  781. smimeekp = SECITEM_AllocItem(poolp, NULL, 0);
  782. if (smimeekp == NULL)
  783. goto loser;
  784. /* create new signing time attribute */
  785. if (NSS_SMIMEUtil_CreateMSSMIMEEncKeyPrefs(poolp, smimeekp, cert) != SECSuccess)
  786. goto loser;
  787. if ((attr = NSS_CMSAttribute_Create(poolp, SEC_OID_MS_SMIME_ENCRYPTION_KEY_PREFERENCE, smimeekp, PR_TRUE)) == NULL)
  788. goto loser;
  789. if (NSS_CMSSignerInfo_AddAuthAttr(signerinfo, attr) != SECSuccess)
  790. goto loser;
  791. PORT_ArenaUnmark(poolp, mark);
  792. return SECSuccess;
  793. loser:
  794. PORT_ArenaRelease(poolp, mark);
  795. return SECFailure;
  796. }
  797. /*
  798. * NSS_CMSSignerInfo_AddCounterSignature - countersign a signerinfo
  799. *
  800. * 1. digest the DER-encoded signature value of the original signerinfo
  801. * 2. create new signerinfo with correct version, sid, digestAlg
  802. * 3. add message-digest authAttr, but NO content-type
  803. * 4. sign the authAttrs
  804. * 5. DER-encode the new signerInfo
  805. * 6. add the whole thing to original signerInfo's unAuthAttrs
  806. * as a SEC_OID_PKCS9_COUNTER_SIGNATURE attribute
  807. *
  808. * XXXX give back the new signerinfo?
  809. */
  810. SECStatus
  811. NSS_CMSSignerInfo_AddCounterSignature(NSSCMSSignerInfo *signerinfo,
  812. SECOidTag digestalg, CERTCertificate signingcert)
  813. {
  814. /* XXXX TBD XXXX */
  815. return SECFailure;
  816. }
  817. /*
  818. * XXXX the following needs to be done in the S/MIME layer code
  819. * after signature of a signerinfo is verified
  820. */
  821. SECStatus
  822. NSS_SMIMESignerInfo_SaveSMIMEProfile(NSSCMSSignerInfo *signerinfo)
  823. {
  824. CERTCertificate *cert = NULL;
  825. SECItem *profile = NULL;
  826. NSSCMSAttribute *attr;
  827. SECItem *stime = NULL;
  828. SECItem *ekp;
  829. CERTCertDBHandle *certdb;
  830. int save_error;
  831. SECStatus rv;
  832. PRBool must_free_cert = PR_FALSE;
  833. certdb = CERT_GetDefaultCertDB();
  834. /* sanity check - see if verification status is ok (unverified does not count...) */
  835. if (signerinfo->verificationStatus != NSSCMSVS_GoodSignature)
  836. return SECFailure;
  837. /* find preferred encryption cert */
  838. if (!NSS_CMSArray_IsEmpty((void **)signerinfo->authAttr) &&
  839. (attr = NSS_CMSAttributeArray_FindAttrByOidTag(signerinfo->authAttr,
  840. SEC_OID_SMIME_ENCRYPTION_KEY_PREFERENCE, PR_TRUE)) != NULL) { /* we have a SMIME_ENCRYPTION_KEY_PREFERENCE attribute! */
  841. ekp = NSS_CMSAttribute_GetValue(attr);
  842. if (ekp == NULL)
  843. return SECFailure;
  844. /* we assume that all certs coming with the message have been imported to the */
  845. /* temporary database */
  846. cert = NSS_SMIMEUtil_GetCertFromEncryptionKeyPreference(certdb, ekp);
  847. if (cert == NULL)
  848. return SECFailure;
  849. must_free_cert = PR_TRUE;
  850. }
  851. if (cert == NULL) {
  852. /* no preferred cert found?
  853. * find the cert the signerinfo is signed with instead */
  854. cert = NSS_CMSSignerInfo_GetSigningCertificate(signerinfo, certdb);
  855. if (cert == NULL || cert->emailAddr == NULL || !cert->emailAddr[0])
  856. return SECFailure;
  857. }
  858. /* verify this cert for encryption (has been verified for signing so far) */
  859. /* don't verify this cert for encryption. It may just be a signing cert.
  860. * that's OK, we can still save the S/MIME profile. The encryption cert
  861. * should have already been saved */
  862. #ifdef notdef
  863. if (CERT_VerifyCert(certdb, cert, PR_TRUE, certUsageEmailRecipient, PR_Now(), signerinfo->cmsg->pwfn_arg, NULL) != SECSuccess) {
  864. if (must_free_cert)
  865. CERT_DestroyCertificate(cert);
  866. return SECFailure;
  867. }
  868. #endif
  869. /* XXX store encryption cert permanently? */
  870. /*
  871. * Remember the current error set because we do not care about
  872. * anything set by the functions we are about to call.
  873. */
  874. save_error = PORT_GetError();
  875. if (!NSS_CMSArray_IsEmpty((void **)signerinfo->authAttr)) {
  876. attr = NSS_CMSAttributeArray_FindAttrByOidTag(signerinfo->authAttr,
  877. SEC_OID_PKCS9_SMIME_CAPABILITIES,
  878. PR_TRUE);
  879. profile = NSS_CMSAttribute_GetValue(attr);
  880. attr = NSS_CMSAttributeArray_FindAttrByOidTag(signerinfo->authAttr,
  881. SEC_OID_PKCS9_SIGNING_TIME,
  882. PR_TRUE);
  883. stime = NSS_CMSAttribute_GetValue(attr);
  884. }
  885. rv = CERT_SaveSMimeProfile(cert, profile, stime);
  886. if (must_free_cert)
  887. CERT_DestroyCertificate(cert);
  888. /*
  889. * Restore the saved error in case the calls above set a new
  890. * one that we do not actually care about.
  891. */
  892. PORT_SetError(save_error);
  893. return rv;
  894. }
  895. /*
  896. * NSS_CMSSignerInfo_IncludeCerts - set cert chain inclusion mode for this signer
  897. */
  898. SECStatus
  899. NSS_CMSSignerInfo_IncludeCerts(NSSCMSSignerInfo *signerinfo,
  900. NSSCMSCertChainMode cm, SECCertUsage usage)
  901. {
  902. if (signerinfo->cert == NULL)
  903. return SECFailure;
  904. /* don't leak if we get called twice */
  905. if (signerinfo->certList != NULL) {
  906. CERT_DestroyCertificateList(signerinfo->certList);
  907. signerinfo->certList = NULL;
  908. }
  909. switch (cm) {
  910. case NSSCMSCM_None:
  911. signerinfo->certList = NULL;
  912. break;
  913. case NSSCMSCM_CertOnly:
  914. signerinfo->certList = CERT_CertListFromCert(signerinfo->cert);
  915. break;
  916. case NSSCMSCM_CertChain:
  917. signerinfo->certList = CERT_CertChainFromCert(signerinfo->cert,
  918. usage, PR_FALSE);
  919. break;
  920. case NSSCMSCM_CertChainWithRoot:
  921. signerinfo->certList = CERT_CertChainFromCert(signerinfo->cert,
  922. usage, PR_TRUE);
  923. break;
  924. }
  925. if (cm != NSSCMSCM_None && signerinfo->certList == NULL)
  926. return SECFailure;
  927. return SECSuccess;
  928. }