certreq.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  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. #include "cert.h"
  5. #include "certt.h"
  6. #include "secder.h"
  7. #include "keyhi.h"
  8. #include "secitem.h"
  9. #include "secasn1.h"
  10. #include "secerr.h"
  11. SEC_ASN1_MKSUB(SEC_AnyTemplate)
  12. const SEC_ASN1Template CERT_AttributeTemplate[] = {
  13. { SEC_ASN1_SEQUENCE,
  14. 0, NULL, sizeof(CERTAttribute) },
  15. { SEC_ASN1_OBJECT_ID, offsetof(CERTAttribute, attrType) },
  16. { SEC_ASN1_SET_OF | SEC_ASN1_XTRN, offsetof(CERTAttribute, attrValue),
  17. SEC_ASN1_SUB(SEC_AnyTemplate) },
  18. { 0 }
  19. };
  20. const SEC_ASN1Template CERT_SetOfAttributeTemplate[] = {
  21. { SEC_ASN1_SET_OF, 0, CERT_AttributeTemplate },
  22. };
  23. const SEC_ASN1Template CERT_CertificateRequestTemplate[] = {
  24. { SEC_ASN1_SEQUENCE,
  25. 0, NULL, sizeof(CERTCertificateRequest) },
  26. { SEC_ASN1_INTEGER,
  27. offsetof(CERTCertificateRequest, version) },
  28. { SEC_ASN1_INLINE,
  29. offsetof(CERTCertificateRequest, subject),
  30. CERT_NameTemplate },
  31. { SEC_ASN1_INLINE,
  32. offsetof(CERTCertificateRequest, subjectPublicKeyInfo),
  33. CERT_SubjectPublicKeyInfoTemplate },
  34. { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
  35. offsetof(CERTCertificateRequest, attributes),
  36. CERT_SetOfAttributeTemplate },
  37. { 0 }
  38. };
  39. SEC_ASN1_CHOOSER_IMPLEMENT(CERT_CertificateRequestTemplate)
  40. CERTCertificate *
  41. CERT_CreateCertificate(unsigned long serialNumber,
  42. CERTName *issuer,
  43. CERTValidity *validity,
  44. CERTCertificateRequest *req)
  45. {
  46. CERTCertificate *c;
  47. int rv;
  48. PLArenaPool *arena;
  49. arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  50. if (!arena) {
  51. return (0);
  52. }
  53. c = (CERTCertificate *)PORT_ArenaZAlloc(arena, sizeof(CERTCertificate));
  54. if (!c) {
  55. PORT_FreeArena(arena, PR_FALSE);
  56. return 0;
  57. }
  58. c->referenceCount = 1;
  59. c->arena = arena;
  60. /*
  61. * Default is a plain version 1.
  62. * If extensions are added, it will get changed as appropriate.
  63. */
  64. rv = DER_SetUInteger(arena, &c->version, SEC_CERTIFICATE_VERSION_1);
  65. if (rv)
  66. goto loser;
  67. rv = DER_SetUInteger(arena, &c->serialNumber, serialNumber);
  68. if (rv)
  69. goto loser;
  70. rv = CERT_CopyName(arena, &c->issuer, issuer);
  71. if (rv)
  72. goto loser;
  73. rv = CERT_CopyValidity(arena, &c->validity, validity);
  74. if (rv)
  75. goto loser;
  76. rv = CERT_CopyName(arena, &c->subject, &req->subject);
  77. if (rv)
  78. goto loser;
  79. rv = SECKEY_CopySubjectPublicKeyInfo(arena, &c->subjectPublicKeyInfo,
  80. &req->subjectPublicKeyInfo);
  81. if (rv)
  82. goto loser;
  83. return c;
  84. loser:
  85. CERT_DestroyCertificate(c);
  86. return 0;
  87. }
  88. /************************************************************************/
  89. /* It's clear from the comments that the original author of this
  90. * function expected the template for certificate requests to treat
  91. * the attributes as a SET OF ANY. This function expected to be
  92. * passed an array of SECItems each of which contained an already encoded
  93. * Attribute. But the cert request template does not treat the
  94. * Attributes as a SET OF ANY, and AFAIK never has. Instead the template
  95. * encodes attributes as a SET OF xxxxxxx. That is, it expects to encode
  96. * each of the Attributes, not have them pre-encoded. Consequently an
  97. * array of SECItems containing encoded Attributes is of no value to this
  98. * function. But we cannot change the signature of this public function.
  99. * It must continue to take SECItems.
  100. *
  101. * I have recoded this function so that each SECItem contains an
  102. * encoded cert extension. The encoded cert extensions form the list for the
  103. * single attribute of the cert request. In this implementation there is at most
  104. * one attribute and it is always of type SEC_OID_PKCS9_EXTENSION_REQUEST.
  105. */
  106. CERTCertificateRequest *
  107. CERT_CreateCertificateRequest(CERTName *subject,
  108. CERTSubjectPublicKeyInfo *spki,
  109. SECItem **attributes)
  110. {
  111. CERTCertificateRequest *certreq;
  112. PLArenaPool *arena;
  113. CERTAttribute *attribute;
  114. SECOidData *oidData;
  115. SECStatus rv;
  116. int i = 0;
  117. arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  118. if (arena == NULL) {
  119. return NULL;
  120. }
  121. certreq = PORT_ArenaZNew(arena, CERTCertificateRequest);
  122. if (!certreq) {
  123. PORT_FreeArena(arena, PR_FALSE);
  124. return NULL;
  125. }
  126. /* below here it is safe to goto loser */
  127. certreq->arena = arena;
  128. rv = DER_SetUInteger(arena, &certreq->version,
  129. SEC_CERTIFICATE_REQUEST_VERSION);
  130. if (rv != SECSuccess)
  131. goto loser;
  132. rv = CERT_CopyName(arena, &certreq->subject, subject);
  133. if (rv != SECSuccess)
  134. goto loser;
  135. rv = SECKEY_CopySubjectPublicKeyInfo(arena,
  136. &certreq->subjectPublicKeyInfo,
  137. spki);
  138. if (rv != SECSuccess)
  139. goto loser;
  140. certreq->attributes = PORT_ArenaZNewArray(arena, CERTAttribute *, 2);
  141. if (!certreq->attributes)
  142. goto loser;
  143. /* Copy over attribute information */
  144. if (!attributes || !attributes[0]) {
  145. /*
  146. ** Invent empty attribute information. According to the
  147. ** pkcs#10 spec, attributes has this ASN.1 type:
  148. **
  149. ** attributes [0] IMPLICIT Attributes
  150. **
  151. ** Which means, we should create a NULL terminated list
  152. ** with the first entry being NULL;
  153. */
  154. certreq->attributes[0] = NULL;
  155. return certreq;
  156. }
  157. /* allocate space for attributes */
  158. attribute = PORT_ArenaZNew(arena, CERTAttribute);
  159. if (!attribute)
  160. goto loser;
  161. oidData = SECOID_FindOIDByTag(SEC_OID_PKCS9_EXTENSION_REQUEST);
  162. PORT_Assert(oidData);
  163. if (!oidData)
  164. goto loser;
  165. rv = SECITEM_CopyItem(arena, &attribute->attrType, &oidData->oid);
  166. if (rv != SECSuccess)
  167. goto loser;
  168. for (i = 0; attributes[i] != NULL; i++)
  169. ;
  170. attribute->attrValue = PORT_ArenaZNewArray(arena, SECItem *, i + 1);
  171. if (!attribute->attrValue)
  172. goto loser;
  173. /* copy attributes */
  174. for (i = 0; attributes[i]; i++) {
  175. /*
  176. ** Attributes are a SetOf Attribute which implies
  177. ** lexigraphical ordering. It is assumes that the
  178. ** attributes are passed in sorted. If we need to
  179. ** add functionality to sort them, there is an
  180. ** example in the PKCS 7 code.
  181. */
  182. attribute->attrValue[i] = SECITEM_ArenaDupItem(arena, attributes[i]);
  183. if (!attribute->attrValue[i])
  184. goto loser;
  185. }
  186. certreq->attributes[0] = attribute;
  187. return certreq;
  188. loser:
  189. CERT_DestroyCertificateRequest(certreq);
  190. return NULL;
  191. }
  192. void
  193. CERT_DestroyCertificateRequest(CERTCertificateRequest *req)
  194. {
  195. if (req && req->arena) {
  196. PORT_FreeArena(req->arena, PR_FALSE);
  197. }
  198. return;
  199. }
  200. static void
  201. setCRExt(void *o, CERTCertExtension **exts)
  202. {
  203. ((CERTCertificateRequest *)o)->attributes = (struct CERTAttributeStr **)exts;
  204. }
  205. /*
  206. ** Set up to start gathering cert extensions for a cert request.
  207. ** The list is created as CertExtensions and converted to an
  208. ** attribute list by CERT_FinishCRAttributes().
  209. */
  210. extern void *cert_StartExtensions(void *owner, PLArenaPool *ownerArena,
  211. void (*setExts)(void *object, CERTCertExtension **exts));
  212. void *
  213. CERT_StartCertificateRequestAttributes(CERTCertificateRequest *req)
  214. {
  215. return (cert_StartExtensions((void *)req, req->arena, setCRExt));
  216. }
  217. /*
  218. ** At entry req->attributes actually contains an list of cert extensions--
  219. ** req-attributes is overloaded until the list is DER encoded (the first
  220. ** ...EncodeItem() below).
  221. ** We turn this into an attribute list by encapsulating it
  222. ** in a PKCS 10 Attribute structure
  223. */
  224. SECStatus
  225. CERT_FinishCertificateRequestAttributes(CERTCertificateRequest *req)
  226. {
  227. SECItem *extlist;
  228. SECOidData *oidrec;
  229. CERTAttribute *attribute;
  230. if (!req || !req->arena) {
  231. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  232. return SECFailure;
  233. }
  234. if (req->attributes == NULL || req->attributes[0] == NULL)
  235. return SECSuccess;
  236. extlist = SEC_ASN1EncodeItem(req->arena, NULL, &req->attributes,
  237. SEC_ASN1_GET(CERT_SequenceOfCertExtensionTemplate));
  238. if (extlist == NULL)
  239. return (SECFailure);
  240. oidrec = SECOID_FindOIDByTag(SEC_OID_PKCS9_EXTENSION_REQUEST);
  241. if (oidrec == NULL)
  242. return SECFailure;
  243. /* now change the list of cert extensions into a list of attributes
  244. */
  245. req->attributes = PORT_ArenaZNewArray(req->arena, CERTAttribute *, 2);
  246. attribute = PORT_ArenaZNew(req->arena, CERTAttribute);
  247. if (req->attributes == NULL || attribute == NULL ||
  248. SECITEM_CopyItem(req->arena, &attribute->attrType, &oidrec->oid) != 0) {
  249. PORT_SetError(SEC_ERROR_NO_MEMORY);
  250. return SECFailure;
  251. }
  252. attribute->attrValue = PORT_ArenaZNewArray(req->arena, SECItem *, 2);
  253. if (attribute->attrValue == NULL)
  254. return SECFailure;
  255. attribute->attrValue[0] = extlist;
  256. attribute->attrValue[1] = NULL;
  257. req->attributes[0] = attribute;
  258. req->attributes[1] = NULL;
  259. return SECSuccess;
  260. }
  261. SECStatus
  262. CERT_GetCertificateRequestExtensions(CERTCertificateRequest *req,
  263. CERTCertExtension ***exts)
  264. {
  265. if (req == NULL || exts == NULL) {
  266. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  267. return SECFailure;
  268. }
  269. if (req->attributes == NULL || *req->attributes == NULL)
  270. return SECSuccess;
  271. if ((*req->attributes)->attrValue == NULL) {
  272. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  273. return SECFailure;
  274. }
  275. return (SEC_ASN1DecodeItem(req->arena, exts,
  276. SEC_ASN1_GET(CERT_SequenceOfCertExtensionTemplate),
  277. (*req->attributes)->attrValue[0]));
  278. }