crmfdec.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. /* -*- Mode: C; tab-width: 8 -*-*/
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "crmf.h"
  6. #include "crmfi.h"
  7. #include "secitem.h"
  8. static CRMFPOPChoice
  9. crmf_get_popchoice_from_der(SECItem *derPOP)
  10. {
  11. CRMFPOPChoice retChoice;
  12. switch (derPOP->data[0] & 0x0f) {
  13. case 0:
  14. retChoice = crmfRAVerified;
  15. break;
  16. case 1:
  17. retChoice = crmfSignature;
  18. break;
  19. case 2:
  20. retChoice = crmfKeyEncipherment;
  21. break;
  22. case 3:
  23. retChoice = crmfKeyAgreement;
  24. break;
  25. default:
  26. retChoice = crmfNoPOPChoice;
  27. break;
  28. }
  29. return retChoice;
  30. }
  31. static SECStatus
  32. crmf_decode_process_raverified(CRMFCertReqMsg *inCertReqMsg)
  33. {
  34. CRMFProofOfPossession *pop;
  35. /* Just set up the structure so that the message structure
  36. * looks like one that was created using the API
  37. */
  38. pop = inCertReqMsg->pop;
  39. pop->popChoice.raVerified.data = NULL;
  40. pop->popChoice.raVerified.len = 0;
  41. return SECSuccess;
  42. }
  43. static SECStatus
  44. crmf_decode_process_signature(CRMFCertReqMsg *inCertReqMsg)
  45. {
  46. PORT_Assert(inCertReqMsg->poolp);
  47. if (!inCertReqMsg->poolp) {
  48. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  49. return SECFailure;
  50. }
  51. return SEC_ASN1Decode(inCertReqMsg->poolp,
  52. &inCertReqMsg->pop->popChoice.signature,
  53. CRMFPOPOSigningKeyTemplate,
  54. (const char *)inCertReqMsg->derPOP.data,
  55. inCertReqMsg->derPOP.len);
  56. }
  57. static CRMFPOPOPrivKeyChoice
  58. crmf_get_messagechoice_from_der(SECItem *derPOP)
  59. {
  60. CRMFPOPOPrivKeyChoice retChoice;
  61. switch (derPOP->data[2] & 0x0f) {
  62. case 0:
  63. retChoice = crmfThisMessage;
  64. break;
  65. case 1:
  66. retChoice = crmfSubsequentMessage;
  67. break;
  68. case 2:
  69. retChoice = crmfDHMAC;
  70. break;
  71. default:
  72. retChoice = crmfNoMessage;
  73. }
  74. return retChoice;
  75. }
  76. static SECStatus
  77. crmf_decode_process_popoprivkey(CRMFCertReqMsg *inCertReqMsg)
  78. {
  79. /* We've got a union, so a pointer to one POPOPrivKey
  80. * struct is the same as having a pointer to the other
  81. * one.
  82. */
  83. CRMFPOPOPrivKey *popoPrivKey =
  84. &inCertReqMsg->pop->popChoice.keyEncipherment;
  85. SECItem *derPOP, privKeyDer;
  86. SECStatus rv;
  87. derPOP = &inCertReqMsg->derPOP;
  88. popoPrivKey->messageChoice = crmf_get_messagechoice_from_der(derPOP);
  89. if (popoPrivKey->messageChoice == crmfNoMessage) {
  90. return SECFailure;
  91. }
  92. /* If we ever encounter BER encodings of this, we'll get in trouble*/
  93. switch (popoPrivKey->messageChoice) {
  94. case crmfThisMessage:
  95. case crmfDHMAC:
  96. privKeyDer.type = derPOP->type;
  97. privKeyDer.data = &derPOP->data[5];
  98. privKeyDer.len = derPOP->len - 5;
  99. break;
  100. case crmfSubsequentMessage:
  101. privKeyDer.type = derPOP->type;
  102. privKeyDer.data = &derPOP->data[4];
  103. privKeyDer.len = derPOP->len - 4;
  104. break;
  105. default:
  106. return SECFailure;
  107. }
  108. rv = SECITEM_CopyItem(inCertReqMsg->poolp,
  109. &popoPrivKey->message.subsequentMessage,
  110. &privKeyDer);
  111. if (rv != SECSuccess) {
  112. return rv;
  113. }
  114. if (popoPrivKey->messageChoice == crmfThisMessage ||
  115. popoPrivKey->messageChoice == crmfDHMAC) {
  116. popoPrivKey->message.thisMessage.len =
  117. CRMF_BYTES_TO_BITS(privKeyDer.len) - (int)derPOP->data[4];
  118. }
  119. return SECSuccess;
  120. }
  121. static SECStatus
  122. crmf_decode_process_keyagreement(CRMFCertReqMsg *inCertReqMsg)
  123. {
  124. return crmf_decode_process_popoprivkey(inCertReqMsg);
  125. }
  126. static SECStatus
  127. crmf_decode_process_keyencipherment(CRMFCertReqMsg *inCertReqMsg)
  128. {
  129. SECStatus rv;
  130. rv = crmf_decode_process_popoprivkey(inCertReqMsg);
  131. if (rv != SECSuccess) {
  132. return rv;
  133. }
  134. if (inCertReqMsg->pop->popChoice.keyEncipherment.messageChoice ==
  135. crmfDHMAC) {
  136. /* Key Encipherment can not use the dhMAC option for
  137. * POPOPrivKey.
  138. */
  139. return SECFailure;
  140. }
  141. return SECSuccess;
  142. }
  143. static SECStatus
  144. crmf_decode_process_pop(CRMFCertReqMsg *inCertReqMsg)
  145. {
  146. SECItem *derPOP;
  147. PLArenaPool *poolp;
  148. CRMFProofOfPossession *pop;
  149. void *mark;
  150. SECStatus rv;
  151. derPOP = &inCertReqMsg->derPOP;
  152. poolp = inCertReqMsg->poolp;
  153. if (derPOP->data == NULL) {
  154. /* There is no Proof of Possession field in this message. */
  155. return SECSuccess;
  156. }
  157. mark = PORT_ArenaMark(poolp);
  158. pop = PORT_ArenaZNew(poolp, CRMFProofOfPossession);
  159. if (pop == NULL) {
  160. goto loser;
  161. }
  162. pop->popUsed = crmf_get_popchoice_from_der(derPOP);
  163. if (pop->popUsed == crmfNoPOPChoice) {
  164. /* A bad encoding of CRMF. Not a valid tag was given to the
  165. * Proof Of Possession field.
  166. */
  167. goto loser;
  168. }
  169. inCertReqMsg->pop = pop;
  170. switch (pop->popUsed) {
  171. case crmfRAVerified:
  172. rv = crmf_decode_process_raverified(inCertReqMsg);
  173. break;
  174. case crmfSignature:
  175. rv = crmf_decode_process_signature(inCertReqMsg);
  176. break;
  177. case crmfKeyEncipherment:
  178. rv = crmf_decode_process_keyencipherment(inCertReqMsg);
  179. break;
  180. case crmfKeyAgreement:
  181. rv = crmf_decode_process_keyagreement(inCertReqMsg);
  182. break;
  183. default:
  184. rv = SECFailure;
  185. }
  186. if (rv != SECSuccess) {
  187. goto loser;
  188. }
  189. PORT_ArenaUnmark(poolp, mark);
  190. return SECSuccess;
  191. loser:
  192. PORT_ArenaRelease(poolp, mark);
  193. inCertReqMsg->pop = NULL;
  194. return SECFailure;
  195. }
  196. static SECStatus
  197. crmf_decode_process_single_control(PLArenaPool *poolp,
  198. CRMFControl *inControl)
  199. {
  200. const SEC_ASN1Template *asn1Template = NULL;
  201. inControl->tag = SECOID_FindOIDTag(&inControl->derTag);
  202. asn1Template = crmf_get_pkiarchiveoptions_subtemplate(inControl);
  203. PORT_Assert(asn1Template != NULL);
  204. PORT_Assert(poolp != NULL);
  205. if (!asn1Template || !poolp) {
  206. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  207. return SECFailure;
  208. }
  209. /* We've got a union, so passing a pointer to one element of the
  210. * union is the same as passing a pointer to any of the other
  211. * members of the union.
  212. */
  213. return SEC_ASN1Decode(poolp, &inControl->value.archiveOptions,
  214. asn1Template, (const char *)inControl->derValue.data,
  215. inControl->derValue.len);
  216. }
  217. static SECStatus
  218. crmf_decode_process_controls(CRMFCertReqMsg *inCertReqMsg)
  219. {
  220. int i, numControls;
  221. SECStatus rv;
  222. PLArenaPool *poolp;
  223. CRMFControl **controls;
  224. numControls = CRMF_CertRequestGetNumControls(inCertReqMsg->certReq);
  225. controls = inCertReqMsg->certReq->controls;
  226. poolp = inCertReqMsg->poolp;
  227. for (i = 0; i < numControls; i++) {
  228. rv = crmf_decode_process_single_control(poolp, controls[i]);
  229. if (rv != SECSuccess) {
  230. return SECFailure;
  231. }
  232. }
  233. return SECSuccess;
  234. }
  235. static SECStatus
  236. crmf_decode_process_single_reqmsg(CRMFCertReqMsg *inCertReqMsg)
  237. {
  238. SECStatus rv;
  239. rv = crmf_decode_process_pop(inCertReqMsg);
  240. if (rv != SECSuccess) {
  241. goto loser;
  242. }
  243. rv = crmf_decode_process_controls(inCertReqMsg);
  244. if (rv != SECSuccess) {
  245. goto loser;
  246. }
  247. inCertReqMsg->certReq->certTemplate.numExtensions =
  248. CRMF_CertRequestGetNumberOfExtensions(inCertReqMsg->certReq);
  249. inCertReqMsg->isDecoded = PR_TRUE;
  250. rv = SECSuccess;
  251. loser:
  252. return rv;
  253. }
  254. CRMFCertReqMsg *
  255. CRMF_CreateCertReqMsgFromDER(const char *buf, long len)
  256. {
  257. PLArenaPool *poolp;
  258. CRMFCertReqMsg *certReqMsg;
  259. SECStatus rv;
  260. poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
  261. if (poolp == NULL) {
  262. goto loser;
  263. }
  264. certReqMsg = PORT_ArenaZNew(poolp, CRMFCertReqMsg);
  265. if (certReqMsg == NULL) {
  266. goto loser;
  267. }
  268. certReqMsg->poolp = poolp;
  269. rv = SEC_ASN1Decode(poolp, certReqMsg, CRMFCertReqMsgTemplate, buf, len);
  270. if (rv != SECSuccess) {
  271. goto loser;
  272. }
  273. rv = crmf_decode_process_single_reqmsg(certReqMsg);
  274. if (rv != SECSuccess) {
  275. goto loser;
  276. }
  277. return certReqMsg;
  278. loser:
  279. if (poolp != NULL) {
  280. PORT_FreeArena(poolp, PR_FALSE);
  281. }
  282. return NULL;
  283. }
  284. CRMFCertReqMessages *
  285. CRMF_CreateCertReqMessagesFromDER(const char *buf, long len)
  286. {
  287. long arenaSize;
  288. int i;
  289. SECStatus rv;
  290. PLArenaPool *poolp;
  291. CRMFCertReqMessages *certReqMsgs;
  292. PORT_Assert(buf != NULL);
  293. /* Wanna make sure the arena is big enough to store all of the requests
  294. * coming in. We'll guestimate according to the length of the buffer.
  295. */
  296. arenaSize = len + len / 2;
  297. poolp = PORT_NewArena(arenaSize);
  298. if (poolp == NULL) {
  299. return NULL;
  300. }
  301. certReqMsgs = PORT_ArenaZNew(poolp, CRMFCertReqMessages);
  302. if (certReqMsgs == NULL) {
  303. goto loser;
  304. }
  305. certReqMsgs->poolp = poolp;
  306. rv = SEC_ASN1Decode(poolp, certReqMsgs, CRMFCertReqMessagesTemplate,
  307. buf, len);
  308. if (rv != SECSuccess) {
  309. goto loser;
  310. }
  311. for (i = 0; certReqMsgs->messages[i] != NULL; i++) {
  312. /* The sub-routines expect the individual messages to have
  313. * an arena. We'll give them one temporarily.
  314. */
  315. certReqMsgs->messages[i]->poolp = poolp;
  316. rv = crmf_decode_process_single_reqmsg(certReqMsgs->messages[i]);
  317. if (rv != SECSuccess) {
  318. goto loser;
  319. }
  320. certReqMsgs->messages[i]->poolp = NULL;
  321. }
  322. return certReqMsgs;
  323. loser:
  324. PORT_FreeArena(poolp, PR_FALSE);
  325. return NULL;
  326. }