1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
52 #define DEFAULT_ALLOC_SIZE 200
53 #define DEFAULT_CGI_VARS 20
55 typedef struct CGIVariableStr
{
60 typedef struct CGIVarTableStr
{
61 CGIVariable
**variables
;
66 typedef struct CertResponseInfoStr
{
67 CERTCertificate
*cert
;
71 typedef struct ChallengeCreationInfoStr
{
73 SECKEYPublicKey
*pubKey
;
74 } ChallengeCreationInfo
;
76 char *missingVar
= NULL
;
85 REQ_CGI_VAR_NOT_PRESENT
,
90 COULD_NOT_DECODE_REQS
,
92 ERROR_RETRIEVING_REQUEST_MSG
,
93 ERROR_RETRIEVING_CERT_REQUEST
,
94 ERROR_RETRIEVING_SUBJECT_FROM_REQ
,
95 ERROR_RETRIEVING_PUBLIC_KEY_FROM_REQ
,
96 ERROR_CREATING_NEW_CERTIFICATE
,
97 COULD_NOT_START_EXTENSIONS
,
98 ERROR_RETRIEVING_EXT_FROM_REQ
,
99 ERROR_ADDING_EXT_TO_CERT
,
100 ERROR_ENDING_EXTENSIONS
,
101 COULD_NOT_FIND_ISSUER_PRIVATE_KEY
,
102 UNSUPPORTED_SIGN_OPERATION_FOR_ISSUER
,
103 ERROR_SETTING_SIGN_ALG
,
104 ERROR_ENCODING_NEW_CERT
,
105 ERROR_SIGNING_NEW_CERT
,
106 ERROR_CREATING_CERT_REP_CONTENT
,
107 ERROR_CREATING_SINGLE_CERT_RESPONSE
,
108 ERROR_SETTING_CERT_RESPONSES
,
109 ERROR_CREATING_CA_LIST
,
110 ERROR_ADDING_ISSUER_TO_CA_LIST
,
111 ERROR_ENCODING_CERT_REP_CONTENT
,
114 ERROR_RETRIEVING_POP_SIGN_KEY
,
115 ERROR_RETRIEVING_ALG_ID_FROM_SIGN_KEY
,
116 ERROR_RETRIEVING_SIGNATURE_FROM_POP_SIGN_KEY
,
117 DO_CHALLENGE_RESPONSE
,
118 ERROR_RETRIEVING_PUB_KEY_FROM_NEW_CERT
,
119 ERROR_ENCODING_CERT_REQ_FOR_POP
,
120 ERROR_VERIFYING_SIGNATURE_POP
,
121 ERROR_RETRIEVING_PUB_KEY_FOR_CHALL
,
122 ERROR_CREATING_EMPTY_CHAL_CONTENT
,
123 ERROR_EXTRACTING_GEN_NAME_FROM_ISSUER
,
124 ERROR_SETTING_CHALLENGE
,
125 ERROR_ENCODING_CHALL
,
126 ERROR_CONVERTING_CHALL_TO_BASE64
,
127 ERROR_CONVERTING_RESP_FROM_CHALL_TO_BIN
,
128 ERROR_CREATING_KEY_RESP_FROM_DER
,
129 ERROR_RETRIEVING_CLIENT_RESPONSE_TO_CHALLENGE
,
130 ERROR_RETURNED_CHALL_NOT_VALUE_EXPECTED
,
131 ERROR_GETTING_KEY_ENCIPHERMENT
,
132 ERROR_NO_POP_FOR_PRIVKEY
,
133 ERROR_UNSUPPORTED_POPOPRIVKEY_TYPE
137 CGITableFindValue(CGIVarTable
*varTable
, const char *key
);
142 printf("Content-type: text/html\n\n");
146 dumpRequest(CGIVarTable
*varTable
)
151 printf ("<table border=1 cellpadding=1 cellspacing=1 width=\"100%%\">\n");
152 printf ("<tr><td><b><center>Variable Name<center></b></td>"
153 "<td><b><center>Value</center></b></td></tr>\n");
154 for (i
=0; i
<varTable
->numVars
; i
++) {
155 var
= varTable
->variables
[i
];
156 printf ("<tr><td><pre>%s</pre></td><td><pre>%s</pre></td></tr>\n",
157 var
->name
, var
->value
);
159 printf("</table>\n");
163 echo_request(CGIVarTable
*varTable
)
166 printf("<html><head><title>CGI Echo Page</title></head>\n"
167 "<body><h1>Got the following request</h1>\n");
168 dumpRequest(varTable
);
169 printf("</body></html>");
173 processVariable(CGIVariable
*var
)
175 char *plusSign
, *percentSign
;
177 /*First look for all of the '+' and convert them to spaces */
178 plusSign
= var
->value
;
179 while ((plusSign
=strchr(plusSign
, '+')) != NULL
) {
182 percentSign
= var
->value
;
183 while ((percentSign
=strchr(percentSign
, '%')) != NULL
) {
187 string
[0] = percentSign
[1];
188 string
[1] = percentSign
[2];
191 sscanf(string
,"%x", &value
);
192 *percentSign
= (char)value
;
193 memmove(&percentSign
[1], &percentSign
[3], 1+strlen(&percentSign
[3]));
198 parseNextVariable(CGIVarTable
*varTable
, char *form_output
)
200 char *ampersand
, *equal
;
203 if (varTable
->numVars
== varTable
->numAlloc
) {
204 CGIVariable
**newArr
= realloc(varTable
->variables
,
205 (varTable
->numAlloc
+ DEFAULT_CGI_VARS
)*sizeof(CGIVariable
*));
206 if (newArr
== NULL
) {
209 varTable
->variables
= newArr
;
210 varTable
->numAlloc
+= DEFAULT_CGI_VARS
;
212 equal
= strchr(form_output
, '=');
216 ampersand
= strchr(equal
, '&');
217 if (ampersand
== NULL
) {
221 if (ampersand
!= NULL
) {
224 var
= malloc(sizeof(CGIVariable
));
225 var
->name
= form_output
;
226 var
->value
= &equal
[1];
227 varTable
->variables
[varTable
->numVars
] = var
;
229 processVariable(var
);
230 return (ampersand
!= NULL
) ? &ersand
[1] : NULL
;
234 ParseInputVariables(CGIVarTable
*varTable
, char *form_output
)
236 varTable
->variables
= malloc(sizeof(CGIVariable
*)*DEFAULT_CGI_VARS
);
237 varTable
->numVars
= 0;
238 varTable
->numAlloc
= DEFAULT_CGI_VARS
;
239 while (form_output
&& form_output
[0] != '\0') {
240 form_output
= parseNextVariable(varTable
, form_output
);
245 CGITableFindValue(CGIVarTable
*varTable
, const char *key
)
247 const char *retVal
= NULL
;
250 for (i
=0; i
<varTable
->numVars
; i
++) {
251 if (strcmp(varTable
->variables
[i
]->name
, key
) == 0) {
252 retVal
= varTable
->variables
[i
]->value
;
260 passwordCallback(PK11SlotInfo
*slot
, PRBool retry
, void *arg
)
266 passwd
= CGITableFindValue((CGIVarTable
*)arg
, "dbPassword");
267 if (passwd
== NULL
) {
270 return PORT_Strdup(passwd
);
274 initNSS(CGIVarTable
*varTable
)
277 PK11SlotInfo
*keySlot
;
280 nssDir
= CGITableFindValue(varTable
,"NSSDirectory");
281 if (nssDir
== NULL
) {
282 missingVar
= "NSSDirectory";
283 return REQ_CGI_VAR_NOT_PRESENT
;
285 rv
= NSS_Init(nssDir
);
286 if (rv
!= SECSuccess
) {
287 return NSS_INIT_FAILED
;
289 PK11_SetPasswordFunc(passwordCallback
);
290 keySlot
= PK11_GetInternalKeySlot();
291 rv
= PK11_Authenticate(keySlot
, PR_FALSE
, varTable
);
292 PK11_FreeSlot(keySlot
);
293 if (rv
!= SECSuccess
) {
300 dumpErrorMessage(ErrorCode errNum
)
303 printf("<html><head><title>Error</title></head><body><h1>Error processing "
304 "data</h1> Received the error %d<p>", errNum
);
305 if (errNum
== REQ_CGI_VAR_NOT_PRESENT
) {
306 printf ("The missing variable is %s.", missingVar
);
308 printf ("<i>More useful information here in the future.</i></body></html>");
312 initOldCertReq(CERTCertificateRequest
*oldCertReq
,
313 CERTName
*subject
, CERTSubjectPublicKeyInfo
*spki
)
317 poolp
= oldCertReq
->arena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
318 SEC_ASN1EncodeInteger(poolp
, &oldCertReq
->version
,
319 SEC_CERTIFICATE_VERSION_3
);
320 CERT_CopyName(poolp
, &oldCertReq
->subject
, subject
);
321 SECKEY_CopySubjectPublicKeyInfo(poolp
, &oldCertReq
->subjectPublicKeyInfo
,
323 oldCertReq
->attributes
= NULL
;
328 addExtensions(CERTCertificate
*newCert
, CRMFCertRequest
*certReq
)
330 int numExtensions
, i
;
332 ErrorCode rv
= NO_ERROR
;
333 CRMFCertExtension
*ext
;
336 numExtensions
= CRMF_CertRequestGetNumberOfExtensions(certReq
);
337 if (numExtensions
== 0) {
338 /* No extensions to add */
341 extHandle
= CERT_StartCertExtensions(newCert
);
342 if (extHandle
== NULL
) {
343 rv
= COULD_NOT_START_EXTENSIONS
;
346 for (i
=0; i
<numExtensions
; i
++) {
347 ext
= CRMF_CertRequestGetExtensionAtIndex(certReq
, i
);
349 rv
= ERROR_RETRIEVING_EXT_FROM_REQ
;
351 srv
= CERT_AddExtension(extHandle
, CRMF_CertExtensionGetOidTag(ext
),
352 CRMF_CertExtensionGetValue(ext
),
353 CRMF_CertExtensionGetIsCritical(ext
), PR_FALSE
);
354 if (srv
!= SECSuccess
) {
355 rv
= ERROR_ADDING_EXT_TO_CERT
;
358 srv
= CERT_FinishExtensions(extHandle
);
359 if (srv
!= SECSuccess
) {
360 rv
= ERROR_ENDING_EXTENSIONS
;
369 writeOutItem(const char *filePath
, SECItem
*der
)
373 outfile
= PR_Open (filePath
,
374 PR_WRONLY
| PR_CREATE_FILE
| PR_TRUNCATE
,
376 PR_Write(outfile
, der
->data
, der
->len
);
382 createNewCert(CERTCertificate
**issuedCert
,CERTCertificateRequest
*oldCertReq
,
383 CRMFCertReqMsg
*currReq
, CRMFCertRequest
*certReq
,
384 CERTCertificate
*issuerCert
, CGIVarTable
*varTable
)
386 CERTCertificate
*newCert
= NULL
;
387 CERTValidity
*validity
;
388 PRExplodedTime printableTime
;
390 ErrorCode rv
=NO_ERROR
;
391 SECKEYPrivateKey
*issuerPrivKey
;
392 SECItem derCert
= { 0 };
398 PR_ExplodeTime(now
, PR_GMTParameters
, &printableTime
);
399 printableTime
.tm_month
+= 9;
400 after
= PR_ImplodeTime(&printableTime
);
401 validity
= CERT_CreateValidity(now
, after
);
402 newCert
= *issuedCert
=
403 CERT_CreateCertificate(rand(), &(issuerCert
->subject
), validity
,
405 if (newCert
== NULL
) {
406 rv
= ERROR_CREATING_NEW_CERTIFICATE
;
409 rv
= addExtensions(newCert
, certReq
);
410 if (rv
!= NO_ERROR
) {
413 issuerPrivKey
= PK11_FindKeyByAnyCert(issuerCert
, varTable
);
414 if (issuerPrivKey
== NULL
) {
415 rv
= COULD_NOT_FIND_ISSUER_PRIVATE_KEY
;
417 signTag
= SEC_GetSignatureAlgorithmOidTag(issuerPrivatekey
->keytype
,
419 if (signTag
== SEC_OID_UNKNOWN
) {
420 rv
= UNSUPPORTED_SIGN_OPERATION_FOR_ISSUER
;
423 srv
= SECOID_SetAlgorithmID(newCert
->arena
, &newCert
->signature
,
425 if (srv
!= SECSuccess
) {
426 rv
= ERROR_SETTING_SIGN_ALG
;
429 srv
= CRMF_CertRequestGetCertTemplateVersion(certReq
, &version
);
430 if (srv
!= SECSuccess
) {
431 /* No version included in the request */
432 *(newCert
->version
.data
) = SEC_CERTIFICATE_VERSION_3
;
434 SECITEM_FreeItem(&newCert
->version
, PR_FALSE
);
435 SEC_ASN1EncodeInteger(newCert
->arena
, &newCert
->version
, version
);
437 SEC_ASN1EncodeItem(newCert
->arena
, &derCert
, newCert
,
438 CERT_CertificateTemplate
);
439 if (derCert
.data
== NULL
) {
440 rv
= ERROR_ENCODING_NEW_CERT
;
443 srv
= SEC_DerSignData(newCert
->arena
, &(newCert
->derCert
), derCert
.data
,
444 derCert
.len
, issuerPrivKey
, signTag
);
445 if (srv
!= SECSuccess
) {
446 rv
= ERROR_SIGNING_NEW_CERT
;
449 #ifdef WRITE_OUT_RESPONSE
450 writeOutItem("newcert.der", &newCert
->derCert
);
456 CERT_DestroyCertificate(newCert
);
463 formatCMMFResponse(char *nickname
, char *base64Response
)
465 char *currLine
, *nextLine
;
467 printf("var retVal = crypto.importUserCertificates(\"%s\",\n", nickname
);
468 currLine
= base64Response
;
470 nextLine
= strchr(currLine
, '\n');
471 if (nextLine
== NULL
) {
472 /* print out the last line here. */
473 printf ("\"%s\",\n", currLine
);
477 printf("\"%s\\n\"+\n", currLine
);
478 currLine
= nextLine
+1;
481 "if(retVal == '') {\n"
482 "\tdocument.write(\"<h1>New Certificate Succesfully Imported.</h1>\");\n"
484 "\tdocument.write(\"<h2>Unable to import New Certificate</h2>\");\n"
485 "\tdocument.write(\"crypto.importUserCertificates returned <b>\");\n"
486 "\tdocument.write(retVal);\n"
487 "\tdocument.write(\"</b>\");\n"
492 spitOutCMMFResponse(char *nickname
, char *base64Response
)
495 printf("<html>\n<head>\n<title>CMMF Resonse Page</title>\n</head>\n\n"
496 "<body><h1>CMMF Response Page</h1>\n"
497 "<script language=\"JavaScript\">\n"
499 formatCMMFResponse(nickname
, base64Response
);
501 "</script>\n</body>\n</html>");
505 getNickname(CERTCertificate
*cert
)
509 if (cert
->nickname
!= NULL
) {
510 return cert
->nickname
;
512 nickname
= CERT_GetCommonName(&cert
->subject
);
513 if (nickname
!= NULL
) {
516 return CERT_NameToAscii(&cert
->subject
);
520 createCMMFResponse(CertResponseInfo
*issuedCerts
, int numCerts
,
521 CERTCertificate
*issuerCert
, char **base64der
)
523 CMMFCertRepContent
*certRepContent
=NULL
;
524 ErrorCode rv
= NO_ERROR
;
525 CMMFCertResponse
**responses
, *currResponse
;
526 CERTCertList
*caList
;
532 certRepContent
= CMMF_CreateCertRepContent();
533 if (certRepContent
== NULL
) {
534 rv
= ERROR_CREATING_CERT_REP_CONTENT
;
537 responses
= PORT_NewArray(CMMFCertResponse
*, numCerts
);
538 if (responses
== NULL
) {
542 for (i
=0; i
<numCerts
;i
++) {
543 responses
[i
] = currResponse
=
544 CMMF_CreateCertResponse(issuedCerts
[i
].certReqID
);
545 if (currResponse
== NULL
) {
546 rv
= ERROR_CREATING_SINGLE_CERT_RESPONSE
;
549 CMMF_CertResponseSetPKIStatusInfoStatus(currResponse
, cmmfGranted
);
550 CMMF_CertResponseSetCertificate(currResponse
, issuedCerts
[i
].cert
);
552 srv
= CMMF_CertRepContentSetCertResponses(certRepContent
, responses
,
554 if (srv
!= SECSuccess
) {
555 rv
= ERROR_SETTING_CERT_RESPONSES
;
558 caList
= CERT_NewCertList();
559 if (caList
== NULL
) {
560 rv
= ERROR_CREATING_CA_LIST
;
563 srv
= CERT_AddCertToListTail(caList
, issuerCert
);
564 if (srv
!= SECSuccess
) {
565 rv
= ERROR_ADDING_ISSUER_TO_CA_LIST
;
568 srv
= CMMF_CertRepContentSetCAPubs(certRepContent
, caList
);
569 CERT_DestroyCertList(caList
);
570 poolp
= PORT_NewArena(1024);
571 der
= SEC_ASN1EncodeItem(poolp
, NULL
, certRepContent
,
572 CMMFCertRepContentTemplate
);
574 rv
= ERROR_ENCODING_CERT_REP_CONTENT
;
577 #ifdef WRITE_OUT_RESPONSE
578 writeOutItem("CertRepContent.der", der
);
580 *base64der
= BTOA_DataToAscii(der
->data
, der
->len
);
587 issueCerts(CertResponseInfo
*issuedCerts
, int numCerts
,
588 CERTCertificate
*issuerCert
)
591 char *base64Response
;
593 rv
= createCMMFResponse(issuedCerts
, numCerts
, issuerCert
, &base64Response
);
594 if (rv
!= NO_ERROR
) {
597 spitOutCMMFResponse(getNickname(issuedCerts
[0].cert
),base64Response
);
604 verifySignature(CGIVarTable
*varTable
, CRMFCertReqMsg
*currReq
,
605 CRMFCertRequest
*certReq
, CERTCertificate
*newCert
)
608 ErrorCode rv
= NO_ERROR
;
609 CRMFPOPOSigningKey
*signKey
= NULL
;
610 SECAlgorithmID
*algID
= NULL
;
611 SECItem
*signature
= NULL
;
612 SECKEYPublicKey
*pubKey
= NULL
;
613 SECItem
*reqDER
= NULL
;
615 srv
= CRMF_CertReqMsgGetPOPOSigningKey(currReq
, &signKey
);
616 if (srv
!= SECSuccess
|| signKey
== NULL
) {
617 rv
= ERROR_RETRIEVING_POP_SIGN_KEY
;
620 algID
= CRMF_POPOSigningKeyGetAlgID(signKey
);
622 rv
= ERROR_RETRIEVING_ALG_ID_FROM_SIGN_KEY
;
625 signature
= CRMF_POPOSigningKeyGetSignature(signKey
);
626 if (signature
== NULL
) {
627 rv
= ERROR_RETRIEVING_SIGNATURE_FROM_POP_SIGN_KEY
;
630 /* Make the length the number of bytes instead of bits */
631 signature
->len
= (signature
->len
+7)/8;
632 pubKey
= CERT_ExtractPublicKey(newCert
);
633 if (pubKey
== NULL
) {
634 rv
= ERROR_RETRIEVING_PUB_KEY_FROM_NEW_CERT
;
637 reqDER
= SEC_ASN1EncodeItem(NULL
, NULL
, certReq
, CRMFCertRequestTemplate
);
638 if (reqDER
== NULL
) {
639 rv
= ERROR_ENCODING_CERT_REQ_FOR_POP
;
642 srv
= VFY_VerifyDataWithAlgorithmID(reqDER
->data
, reqDER
->len
, pubKey
,
643 signature
, &algID
->algorithm
, NULL
, varTable
);
644 if (srv
!= SECSuccess
) {
645 rv
= ERROR_VERIFYING_SIGNATURE_POP
;
648 /* Fall thru in successfull case. */
650 if (pubKey
!= NULL
) {
651 SECKEY_DestroyPublicKey(pubKey
);
653 if (reqDER
!= NULL
) {
654 SECITEM_FreeItem(reqDER
, PR_TRUE
);
656 if (signature
!= NULL
) {
657 SECITEM_FreeItem(signature
, PR_TRUE
);
660 SECOID_DestroyAlgorithmID(algID
, PR_TRUE
);
662 if (signKey
!= NULL
) {
663 CRMF_DestroyPOPOSigningKey(signKey
);
669 doChallengeResponse(CGIVarTable
*varTable
, CRMFCertReqMsg
*currReq
,
670 CRMFCertRequest
*certReq
, CERTCertificate
*newCert
,
671 ChallengeCreationInfo
*challs
, int *numChall
)
673 CRMFPOPOPrivKey
*privKey
= NULL
;
674 CRMFPOPOPrivKeyChoice privKeyChoice
;
676 ErrorCode rv
= NO_ERROR
;
678 srv
= CRMF_CertReqMsgGetPOPKeyEncipherment(currReq
, &privKey
);
679 if (srv
!= SECSuccess
|| privKey
== NULL
) {
680 rv
= ERROR_GETTING_KEY_ENCIPHERMENT
;
683 privKeyChoice
= CRMF_POPOPrivKeyGetChoice(privKey
);
684 CRMF_DestroyPOPOPrivKey(privKey
);
685 switch (privKeyChoice
) {
686 case crmfSubsequentMessage
:
687 challs
= &challs
[*numChall
];
688 challs
->random
= rand();
689 challs
->pubKey
= CERT_ExtractPublicKey(newCert
);
690 if (challs
->pubKey
== NULL
) {
691 rv
= ERROR_RETRIEVING_PUB_KEY_FOR_CHALL
;
695 rv
= DO_CHALLENGE_RESPONSE
;
697 case crmfThisMessage
:
698 /* There'd better be a PKIArchiveControl in this message */
699 if (!CRMF_CertRequestIsControlPresent(certReq
,
700 crmfPKIArchiveOptionsControl
)) {
701 rv
= ERROR_NO_POP_FOR_PRIVKEY
;
706 rv
= ERROR_UNSUPPORTED_POPOPRIVKEY_TYPE
;
714 doProofOfPossession(CGIVarTable
*varTable
, CRMFCertReqMsg
*currReq
,
715 CRMFCertRequest
*certReq
, CERTCertificate
*newCert
,
716 ChallengeCreationInfo
*challs
, int *numChall
)
718 CRMFPOPChoice popChoice
;
719 ErrorCode rv
= NO_ERROR
;
721 popChoice
= CRMF_CertReqMsgGetPOPType(currReq
);
722 if (popChoice
== crmfNoPOPChoice
) {
723 rv
= NO_POP_FOR_REQUEST
;
728 rv
= verifySignature(varTable
, currReq
, certReq
, newCert
);
730 case crmfKeyEncipherment
:
731 rv
= doChallengeResponse(varTable
, currReq
, certReq
, newCert
,
735 case crmfKeyAgreement
:
737 rv
= UNSUPPORTED_POP
;
745 convertB64ToJS(char *base64
)
749 for (i
=0; base64
[i
] != '\0'; i
++) {
750 if (base64
[i
] == '\n') {
753 printf ("%c", base64
[i
]);
759 formatChallenge(char *chall64
, char *certRepContentDER
,
760 ChallengeCreationInfo
*challInfo
, int numChalls
)
762 printf ("function respondToChallenge() {\n"
763 " var chalForm = document.chalForm;\n\n"
764 " chalForm.CertRepContent.value = '");
765 convertB64ToJS(certRepContentDER
);
767 " chalForm.ChallResponse.value = crypto.popChallengeResponse('");
768 convertB64ToJS(chall64
);
770 " chalForm.submit();\n"
776 spitOutChallenge(char *chall64
, char *certRepContentDER
,
777 ChallengeCreationInfo
*challInfo
, int numChalls
,
785 "<title>Challenge Page</title>\n"
786 "<script language=\"JavaScript\">\n"
788 /* The JavaScript function actually gets defined within
791 formatChallenge(chall64
, certRepContentDER
, challInfo
, numChalls
);
795 "<body onLoad='respondToChallenge()'>\n"
796 "<h1>Cartman is now responding to the Challenge "
797 "presented by the CGI</h1>\n"
798 "<form action='crmfcgi' method='post' name='chalForm'>\n"
799 "<input type='hidden' name=CertRepContent value=''>\n"
800 "<input type='hidden' name=ChallResponse value=''>\n");
801 for (i
=0;i
<numChalls
; i
++) {
802 printf("<input type='hidden' name='chal%d' value='%d'>\n",
803 i
+1, challInfo
[i
].random
);
805 printf("<input type='hidden' name='nickname' value='%s'>\n", nickname
);
806 printf("</form>\n</body>\n</html>");
810 issueChallenge(CertResponseInfo
*issuedCerts
, int numCerts
,
811 ChallengeCreationInfo
*challInfo
, int numChalls
,
812 CERTCertificate
*issuer
, CGIVarTable
*varTable
)
814 ErrorCode rv
= NO_ERROR
;
815 CMMFPOPODecKeyChallContent
*chalContent
= NULL
;
819 CERTGeneralName
*genName
;
820 SECItem
*challDER
= NULL
;
821 char *chall64
, *certRepContentDER
;
823 rv
= createCMMFResponse(issuedCerts
, numCerts
, issuer
,
825 if (rv
!= NO_ERROR
) {
828 chalContent
= CMMF_CreatePOPODecKeyChallContent();
829 if (chalContent
== NULL
) {
830 rv
= ERROR_CREATING_EMPTY_CHAL_CONTENT
;
833 poolp
= PORT_NewArena(1024);
838 genName
= CERT_GetCertificateNames(issuer
, poolp
);
839 if (genName
== NULL
) {
840 rv
= ERROR_EXTRACTING_GEN_NAME_FROM_ISSUER
;
843 for (i
=0;i
<numChalls
;i
++) {
844 srv
= CMMF_POPODecKeyChallContentSetNextChallenge(chalContent
,
849 SECKEY_DestroyPublicKey(challInfo
[i
].pubKey
);
850 if (srv
!= SECSuccess
) {
851 rv
= ERROR_SETTING_CHALLENGE
;
855 challDER
= SEC_ASN1EncodeItem(NULL
, NULL
, chalContent
,
856 CMMFPOPODecKeyChallContentTemplate
);
857 if (challDER
== NULL
) {
858 rv
= ERROR_ENCODING_CHALL
;
861 chall64
= BTOA_DataToAscii(challDER
->data
, challDER
->len
);
862 SECITEM_FreeItem(challDER
, PR_TRUE
);
863 if (chall64
== NULL
) {
864 rv
= ERROR_CONVERTING_CHALL_TO_BASE64
;
867 spitOutChallenge(chall64
, certRepContentDER
, challInfo
, numChalls
,
868 getNickname(issuedCerts
[0].cert
));
875 processRequest(CGIVarTable
*varTable
)
877 CERTCertDBHandle
*certdb
;
878 SECKEYKeyDBHandle
*keydb
;
879 CRMFCertReqMessages
*certReqs
= NULL
;
881 const char *caNickname
;
882 CERTCertificate
*caCert
= NULL
;
883 CertResponseInfo
*issuedCerts
= NULL
;
884 CERTSubjectPublicKeyInfo spki
= { 0 };
885 ErrorCode rv
=NO_ERROR
;
886 PRBool doChallengeResponse
= PR_FALSE
;
889 CERTCertificateRequest oldCertReq
= { 0 };
890 CRMFCertReqMsg
**reqMsgs
= NULL
,*currReq
= NULL
;
891 CRMFCertRequest
**reqs
= NULL
, *certReq
= NULL
;
892 CERTName subject
= { 0 };
894 ChallengeCreationInfo
*challInfo
=NULL
;
897 certdb
= CERT_GetDefaultCertDB();
898 keydb
= SECKEY_GetDefaultKeyDB();
899 crmfReq
= CGITableFindValue(varTable
, "CRMFRequest");
900 if (crmfReq
== NULL
) {
901 rv
= CGI_VAR_MISSING
;
902 missingVar
= "CRMFRequest";
905 caNickname
= CGITableFindValue(varTable
, "CANickname");
906 if (caNickname
== NULL
) {
907 rv
= CGI_VAR_MISSING
;
908 missingVar
= "CANickname";
911 caCert
= CERT_FindCertByNickname(certdb
, caNickname
);
912 if (caCert
== NULL
) {
913 rv
= COULD_NOT_FIND_CA
;
916 srv
= ATOB_ConvertAsciiToItem(&der
, crmfReq
);
917 if (srv
!= SECSuccess
) {
918 rv
= BAD_ASCII_FOR_REQ
;
921 certReqs
= CRMF_CreateCertReqMessagesFromDER(der
.data
, der
.len
);
922 SECITEM_FreeItem(&der
, PR_FALSE
);
923 if (certReqs
== NULL
) {
924 rv
= COULD_NOT_DECODE_REQS
;
927 numReqs
= CRMF_CertReqMessagesGetNumMessages(certReqs
);
928 issuedCerts
= PORT_ZNewArray(CertResponseInfo
, numReqs
);
929 challInfo
= PORT_ZNewArray(ChallengeCreationInfo
, numReqs
);
930 if (issuedCerts
== NULL
|| challInfo
== NULL
) {
934 reqMsgs
= PORT_ZNewArray(CRMFCertReqMsg
*, numReqs
);
935 reqs
= PORT_ZNewArray(CRMFCertRequest
*, numReqs
);
936 if (reqMsgs
== NULL
|| reqs
== NULL
) {
940 for (i
=0; i
<numReqs
; i
++) {
941 currReq
= reqMsgs
[i
] =
942 CRMF_CertReqMessagesGetCertReqMsgAtIndex(certReqs
, i
);
943 if (currReq
== NULL
) {
944 rv
= ERROR_RETRIEVING_REQUEST_MSG
;
947 certReq
= reqs
[i
] = CRMF_CertReqMsgGetCertRequest(currReq
);
948 if (certReq
== NULL
) {
949 rv
= ERROR_RETRIEVING_CERT_REQUEST
;
952 srv
= CRMF_CertRequestGetCertTemplateSubject(certReq
, &subject
);
953 if (srv
!= SECSuccess
) {
954 rv
= ERROR_RETRIEVING_SUBJECT_FROM_REQ
;
957 srv
= CRMF_CertRequestGetCertTemplatePublicKey(certReq
, &spki
);
958 if (srv
!= SECSuccess
) {
959 rv
= ERROR_RETRIEVING_PUBLIC_KEY_FROM_REQ
;
962 rv
= initOldCertReq(&oldCertReq
, &subject
, &spki
);
963 if (rv
!= NO_ERROR
) {
966 rv
= createNewCert(&issuedCerts
[i
].cert
, &oldCertReq
, currReq
, certReq
,
968 if (rv
!= NO_ERROR
) {
971 rv
= doProofOfPossession(varTable
, currReq
, certReq
, issuedCerts
[i
].cert
,
972 challInfo
, &numChalls
);
973 if (rv
!= NO_ERROR
) {
974 if (rv
== DO_CHALLENGE_RESPONSE
) {
975 doChallengeResponse
= PR_TRUE
;
980 CRMF_CertReqMsgGetID(currReq
, &issuedCerts
[i
].certReqID
);
981 CRMF_DestroyCertReqMsg(currReq
);
982 CRMF_DestroyCertRequest(certReq
);
984 if (doChallengeResponse
) {
985 rv
= issueChallenge(issuedCerts
, numReqs
, challInfo
, numChalls
, caCert
,
988 rv
= issueCerts(issuedCerts
, numReqs
, caCert
);
991 if (certReqs
!= NULL
) {
992 CRMF_DestroyCertReqMessages(certReqs
);
998 processChallengeResponse(CGIVarTable
*varTable
, const char *certRepContent
)
1000 SECItem binDER
= { 0 };
1002 ErrorCode rv
= NO_ERROR
;
1003 const char *clientResponse
;
1004 const char *formChalValue
;
1005 const char *nickname
;
1006 CMMFPOPODecKeyRespContent
*respContent
= NULL
;
1008 long curResponse
, expectedResponse
;
1009 char cgiChalVar
[10];
1010 #ifdef WRITE_OUT_RESPONSE
1011 SECItem certRepBinDER
= { 0 };
1013 ATOB_ConvertAsciiToItem(&certRepBinDER
, certRepContent
);
1014 writeOutItem("challCertRepContent.der", &certRepBinDER
);
1015 PORT_Free(certRepBinDER
.data
);
1017 clientResponse
= CGITableFindValue(varTable
, "ChallResponse");
1018 if (clientResponse
== NULL
) {
1019 rv
= REQ_CGI_VAR_NOT_PRESENT
;
1020 missingVar
= "ChallResponse";
1023 srv
= ATOB_ConvertAsciiToItem(&binDER
, clientResponse
);
1024 if (srv
!= SECSuccess
) {
1025 rv
= ERROR_CONVERTING_RESP_FROM_CHALL_TO_BIN
;
1028 respContent
= CMMF_CreatePOPODecKeyRespContentFromDER(binDER
.data
,
1030 SECITEM_FreeItem(&binDER
, PR_FALSE
);
1032 if (respContent
== NULL
) {
1033 rv
= ERROR_CREATING_KEY_RESP_FROM_DER
;
1036 numResponses
= CMMF_POPODecKeyRespContentGetNumResponses(respContent
);
1037 for (i
=0;i
<numResponses
;i
++){
1038 srv
= CMMF_POPODecKeyRespContentGetResponse(respContent
,i
,&curResponse
);
1039 if (srv
!= SECSuccess
) {
1040 rv
= ERROR_RETRIEVING_CLIENT_RESPONSE_TO_CHALLENGE
;
1043 sprintf(cgiChalVar
, "chal%d", i
+1);
1044 formChalValue
= CGITableFindValue(varTable
, cgiChalVar
);
1045 if (formChalValue
== NULL
) {
1046 rv
= REQ_CGI_VAR_NOT_PRESENT
;
1047 missingVar
= strdup(cgiChalVar
);
1050 sscanf(formChalValue
, "%ld", &expectedResponse
);
1051 if (expectedResponse
!= curResponse
) {
1052 rv
= ERROR_RETURNED_CHALL_NOT_VALUE_EXPECTED
;
1056 nickname
= CGITableFindValue(varTable
, "nickname");
1057 if (nickname
== NULL
) {
1058 rv
= REQ_CGI_VAR_NOT_PRESENT
;
1059 missingVar
= "nickname";
1062 spitOutCMMFResponse(nickname
, certRepContent
);
1064 if (respContent
!= NULL
) {
1065 CMMF_DestroyPOPODecKeyRespContent(respContent
);
1073 char *form_output
= NULL
;
1074 int form_output_len
, form_output_used
;
1075 CGIVarTable varTable
= { 0 };
1076 ErrorCode errNum
= 0;
1077 char *certRepContent
;
1080 /* Put an ifinite loop in here so I can attach to
1081 * the process after the process is spun off
1088 form_output_used
= 0;
1090 while (feof(stdin
) == 0) {
1091 if (form_output
== NULL
) {
1092 form_output
= PORT_NewArray(char, DEFAULT_ALLOC_SIZE
+1);
1093 form_output_len
= DEFAULT_ALLOC_SIZE
;
1094 } else if ((form_output_used
+ DEFAULT_ALLOC_SIZE
) >= form_output_len
) {
1095 form_output_len
+= DEFAULT_ALLOC_SIZE
;
1096 form_output
= PORT_Realloc(form_output
, form_output_len
+1);
1098 form_output_used
+= fread(&form_output
[form_output_used
], sizeof(char),
1099 DEFAULT_ALLOC_SIZE
, stdin
);
1101 ParseInputVariables(&varTable
, form_output
);
1102 certRepContent
= CGITableFindValue(&varTable
, "CertRepContent");
1103 if (certRepContent
== NULL
) {
1104 errNum
= initNSS(&varTable
);
1108 errNum
= processRequest(&varTable
);
1110 errNum
= processChallengeResponse(&varTable
, certRepContent
);
1112 if (errNum
!= NO_ERROR
) {
1117 dumpErrorMessage(errNum
);