/security/nss/lib/crmf/crmfdec.c

http://github.com/zpao/v8monkey · C · 395 lines · 297 code · 37 blank · 61 comment · 56 complexity · 9d1cabc94e1f3481d70cd43d4123eeea MD5 · raw file

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