crmfcgi.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:30k
源码类别:

CA认证

开发平台:

WINDOWS

  1. /*
  2.  * The contents of this file are subject to the Mozilla Public
  3.  * License Version 1.1 (the "License"); you may not use this file
  4.  * except in compliance with the License. You may obtain a copy of
  5.  * the License at http://www.mozilla.org/MPL/
  6.  * 
  7.  * Software distributed under the License is distributed on an "AS
  8.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9.  * implied. See the License for the specific language governing
  10.  * rights and limitations under the License.
  11.  * 
  12.  * The Original Code is the Netscape security libraries.
  13.  * 
  14.  * The Initial Developer of the Original Code is Netscape
  15.  * Communications Corporation.  Portions created by Netscape are 
  16.  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
  17.  * Rights Reserved.
  18.  * 
  19.  * Contributor(s):
  20.  * 
  21.  * Alternatively, the contents of this file may be used under the
  22.  * terms of the GNU General Public License Version 2 or later (the
  23.  * "GPL"), in which case the provisions of the GPL are applicable 
  24.  * instead of those above.  If you wish to allow use of your 
  25.  * version of this file only under the terms of the GPL and not to
  26.  * allow others to use your version of this file under the MPL,
  27.  * indicate your decision by deleting the provisions above and
  28.  * replace them with the notice and other provisions required by
  29.  * the GPL.  If you do not delete the provisions above, a recipient
  30.  * may use your version of this file under either the MPL or the
  31.  * GPL.
  32.  */
  33. #include "seccomon.h"
  34. #include "nss.h"
  35. #include "key.h"
  36. #include "cert.h"
  37. #include "pk11func.h"
  38. #include "secmod.h"
  39. #include "cmmf.h"
  40. #include "crmf.h"
  41. #include "base64.h"
  42. #include "secasn1.h"
  43. #include "crypto.h"
  44. #include <string.h>
  45. #include <stdlib.h>
  46. #include <stdio.h>
  47. #define DEFAULT_ALLOC_SIZE 200
  48. #define DEFAULT_CGI_VARS   20
  49. typedef struct CGIVariableStr {
  50.   char *name;
  51.   char *value;
  52. } CGIVariable;
  53. typedef struct CGIVarTableStr {
  54.   CGIVariable **variables;
  55.   int           numVars;
  56.   int           numAlloc; 
  57. } CGIVarTable;
  58. typedef struct CertResponseInfoStr {
  59.   CERTCertificate *cert;
  60.   long             certReqID;
  61. } CertResponseInfo;
  62. typedef struct ChallengeCreationInfoStr {
  63.   long             random;
  64.   SECKEYPublicKey *pubKey;
  65. } ChallengeCreationInfo;
  66. char *missingVar = NULL;
  67. /*
  68.  * Error values.
  69.  */
  70. typedef enum {
  71.   NO_ERROR = 0,
  72.   NSS_INIT_FAILED,
  73.   AUTH_FAILED,
  74.   REQ_CGI_VAR_NOT_PRESENT,
  75.   CRMF_REQ_NOT_PRESENT,
  76.   BAD_ASCII_FOR_REQ,
  77.   CGI_VAR_MISSING,
  78.   COULD_NOT_FIND_CA,
  79.   COULD_NOT_DECODE_REQS,
  80.   OUT_OF_MEMORY,
  81.   ERROR_RETRIEVING_REQUEST_MSG,
  82.   ERROR_RETRIEVING_CERT_REQUEST,
  83.   ERROR_RETRIEVING_SUBJECT_FROM_REQ,
  84.   ERROR_RETRIEVING_PUBLIC_KEY_FROM_REQ,
  85.   ERROR_CREATING_NEW_CERTIFICATE,
  86.   COULD_NOT_START_EXTENSIONS,
  87.   ERROR_RETRIEVING_EXT_FROM_REQ,
  88.   ERROR_ADDING_EXT_TO_CERT,
  89.   ERROR_ENDING_EXTENSIONS,
  90.   COULD_NOT_FIND_ISSUER_PRIVATE_KEY,
  91.   UNSUPPORTED_SIGN_OPERATION_FOR_ISSUER,
  92.   ERROR_SETTING_SIGN_ALG,
  93.   ERROR_ENCODING_NEW_CERT,
  94.   ERROR_SIGNING_NEW_CERT,
  95.   ERROR_CREATING_CERT_REP_CONTENT,
  96.   ERROR_CREATING_SINGLE_CERT_RESPONSE,
  97.   ERROR_SETTING_CERT_RESPONSES,
  98.   ERROR_CREATING_CA_LIST,
  99.   ERROR_ADDING_ISSUER_TO_CA_LIST,
  100.   ERROR_ENCODING_CERT_REP_CONTENT,
  101.   NO_POP_FOR_REQUEST,
  102.   UNSUPPORTED_POP,
  103.   ERROR_RETRIEVING_POP_SIGN_KEY,
  104.   ERROR_RETRIEVING_ALG_ID_FROM_SIGN_KEY,
  105.   ERROR_RETRIEVING_SIGNATURE_FROM_POP_SIGN_KEY,
  106.   DO_CHALLENGE_RESPONSE,
  107.   ERROR_RETRIEVING_PUB_KEY_FROM_NEW_CERT,
  108.   ERROR_ENCODING_CERT_REQ_FOR_POP,
  109.   ERROR_VERIFYING_SIGNATURE_POP,
  110.   ERROR_RETRIEVING_PUB_KEY_FOR_CHALL,
  111.   ERROR_CREATING_EMPTY_CHAL_CONTENT,
  112.   ERROR_EXTRACTING_GEN_NAME_FROM_ISSUER,
  113.   ERROR_SETTING_CHALLENGE,
  114.   ERROR_ENCODING_CHALL,
  115.   ERROR_CONVERTING_CHALL_TO_BASE64,
  116.   ERROR_CONVERTING_RESP_FROM_CHALL_TO_BIN,
  117.   ERROR_CREATING_KEY_RESP_FROM_DER,
  118.   ERROR_RETRIEVING_CLIENT_RESPONSE_TO_CHALLENGE,
  119.   ERROR_RETURNED_CHALL_NOT_VALUE_EXPECTED,
  120.   ERROR_GETTING_KEY_ENCIPHERMENT,
  121.   ERROR_NO_POP_FOR_PRIVKEY,
  122.   ERROR_UNSUPPORTED_POPOPRIVKEY_TYPE
  123. } ErrorCode;
  124. const char *
  125. CGITableFindValue(CGIVarTable *varTable, const char *key);
  126. void
  127. spitOutHeaders(void)
  128. {
  129.   printf("Content-type: text/htmlnn");
  130. }
  131. void
  132. dumpRequest(CGIVarTable *varTable)
  133. {
  134.   int i;
  135.   CGIVariable *var;
  136.   printf ("<table border=1 cellpadding=1 cellspacing=1 width="100%%">n");
  137.   printf ("<tr><td><b><center>Variable Name<center></b></td>"
  138.           "<td><b><center>Value</center></b></td></tr>n");
  139.   for (i=0; i<varTable->numVars; i++) {
  140.     var = varTable->variables[i];
  141.     printf ("<tr><td><pre>%s</pre></td><td><pre>%s</pre></td></tr>n", 
  142.              var->name, var->value);
  143.   }
  144.   printf("</table>n");
  145. }
  146. void
  147. echo_request(CGIVarTable *varTable)
  148. {
  149.   spitOutHeaders();
  150.   printf("<html><head><title>CGI Echo Page</title></head>n"
  151.  "<body><h1>Got the following request</h1>n");
  152.   dumpRequest(varTable);
  153.   printf("</body></html>");
  154. }
  155. void
  156. processVariable(CGIVariable *var)
  157. {
  158.   char *plusSign, *percentSign;
  159.   /*First look for all of the '+' and convert them to spaces */
  160.   plusSign = var->value;
  161.   while ((plusSign=strchr(plusSign, '+')) != NULL) {
  162.     *plusSign = ' ';
  163.   }
  164.   percentSign = var->value;
  165.   while ((percentSign=strchr(percentSign, '%')) != NULL) {
  166.     char string[3];
  167.     int  value;
  168.     string[0] = percentSign[1];
  169.     string[1] = percentSign[2];
  170.     string[2] = '';
  171.     sscanf(string,"%x", &value);
  172.     *percentSign = (char)value;
  173.     memmove(&percentSign[1], &percentSign[3], 1+strlen(&percentSign[3]));
  174.   }
  175. }
  176. char *
  177. parseNextVariable(CGIVarTable *varTable, char *form_output)
  178. {
  179.   char *ampersand, *equal;
  180.   CGIVariable *var;
  181.   if (varTable->numVars == varTable->numAlloc) {
  182.     CGIVariable **newArr = realloc(varTable->variables, 
  183.                                    (varTable->numAlloc + DEFAULT_CGI_VARS)*sizeof(CGIVariable*));
  184.     if (newArr == NULL) {
  185.       return NULL;
  186.     }
  187.     varTable->variables = newArr;
  188.     varTable->numAlloc += DEFAULT_CGI_VARS;
  189.   }
  190.   equal     = strchr(form_output, '=');
  191.   if (equal == NULL) {
  192.     return NULL;
  193.   }
  194.   ampersand = strchr(equal, '&');
  195.   if (ampersand == NULL) {
  196.     return NULL;
  197.   }
  198.   equal[0] = '';
  199.   if (ampersand != NULL) {
  200.     ampersand[0] = '';
  201.   }
  202.   var = malloc(sizeof(CGIVariable));
  203.   var->name = form_output; 
  204.   var->value = &equal[1];
  205.   varTable->variables[varTable->numVars] = var;
  206.   varTable->numVars++;
  207.   processVariable(var);
  208.   return (ampersand != NULL) ? &ampersand[1] : NULL;
  209. }
  210. void
  211. ParseInputVariables(CGIVarTable *varTable, char *form_output)
  212. {
  213.   varTable->variables = malloc(sizeof(CGIVariable*)*DEFAULT_CGI_VARS);
  214.   varTable->numVars = 0;
  215.   varTable->numAlloc = DEFAULT_CGI_VARS;
  216.   while (form_output && form_output[0] != '') {
  217.     form_output = parseNextVariable(varTable, form_output);
  218.   }
  219. }
  220. const char *
  221. CGITableFindValue(CGIVarTable *varTable, const char *key)
  222. {
  223.   const char *retVal = NULL;
  224.   int i;
  225.   for (i=0; i<varTable->numVars; i++) {
  226.     if (strcmp(varTable->variables[i]->name, key) == 0) {
  227.       retVal = varTable->variables[i]->value;
  228.       break;
  229.     } 
  230.   }
  231.   return retVal;
  232. }
  233. char*
  234. passwordCallback(PK11SlotInfo *slot, PRBool retry, void *arg)
  235. {
  236.   const char *passwd;
  237.   if (retry) {
  238.     return NULL;
  239.   }
  240.   passwd = CGITableFindValue((CGIVarTable*)arg, "dbPassword");
  241.   if (passwd == NULL) {
  242.     return NULL;
  243.   }
  244.   return PORT_Strdup(passwd);
  245. }
  246. ErrorCode
  247. initNSS(CGIVarTable *varTable)
  248. {
  249.   const char *nssDir;
  250.   PK11SlotInfo *keySlot;
  251.   SECStatus rv;
  252.   nssDir = CGITableFindValue(varTable,"NSSDirectory");
  253.   if (nssDir == NULL) {
  254.     missingVar = "NSSDirectory";
  255.     return REQ_CGI_VAR_NOT_PRESENT;
  256.   }
  257.   rv = NSS_Init(nssDir);
  258.   if (rv != SECSuccess) {
  259.     return NSS_INIT_FAILED;
  260.   }
  261.   PK11_SetPasswordFunc(passwordCallback);
  262.   keySlot = PK11_GetInternalKeySlot();
  263.   rv = PK11_Authenticate(keySlot, PR_FALSE, varTable);
  264.   if (rv != SECSuccess) {
  265.     return AUTH_FAILED;
  266.   }
  267.   return NO_ERROR;
  268. }
  269. void
  270. dumpErrorMessage(ErrorCode errNum)
  271. {
  272.   spitOutHeaders();
  273.   printf("<html><head><title>Error</title></head><body><h1>Error processing "
  274.  "data</h1> Received the error %d<p>", errNum);
  275.   if (errNum  ==   REQ_CGI_VAR_NOT_PRESENT) {
  276.     printf ("The missing variable is %s.", missingVar);
  277.   }
  278.   printf ("<i>More useful information here in the future.</i></body></html>");
  279. }
  280. ErrorCode
  281. initOldCertReq(CERTCertificateRequest *oldCertReq,
  282.        CERTName *subject, CERTSubjectPublicKeyInfo *spki)
  283. {
  284.   PRArenaPool *poolp;
  285.   poolp = oldCertReq->arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  286.   SEC_ASN1EncodeInteger(poolp, &oldCertReq->version, 
  287. SEC_CERTIFICATE_VERSION_3);
  288.   CERT_CopyName(poolp, &oldCertReq->subject, subject);
  289.   SECKEY_CopySubjectPublicKeyInfo(poolp, &oldCertReq->subjectPublicKeyInfo,
  290.   spki);
  291.   oldCertReq->attributes = NULL;
  292.   return NO_ERROR;
  293. }
  294. ErrorCode
  295. addExtensions(CERTCertificate *newCert, CRMFCertRequest *certReq)
  296. {
  297.   int numExtensions, i;
  298.   void *extHandle;
  299.   ErrorCode rv = NO_ERROR;
  300.   CRMFCertExtension *ext;
  301.   SECStatus srv;
  302.   numExtensions = CRMF_CertRequestGetNumberOfExtensions(certReq);
  303.   if (numExtensions == 0) {
  304.     /* No extensions to add */
  305.     return NO_ERROR;
  306.   }
  307.   extHandle = CERT_StartCertExtensions(newCert);
  308.   if (extHandle == NULL) {
  309.     rv = COULD_NOT_START_EXTENSIONS;
  310.     goto loser;
  311.   }
  312.   for (i=0; i<numExtensions; i++) {
  313.     ext = CRMF_CertRequestGetExtensionAtIndex(certReq, i);
  314.     if (ext == NULL) {
  315.       rv = ERROR_RETRIEVING_EXT_FROM_REQ;
  316.     }
  317.     srv = CERT_AddExtension(extHandle, CRMF_CertExtensionGetOidTag(ext),
  318.     CRMF_CertExtensionGetValue(ext),
  319.     CRMF_CertExtensionGetIsCritical(ext), PR_FALSE);
  320.     if (srv != SECSuccess) {
  321.       rv = ERROR_ADDING_EXT_TO_CERT;
  322.     }
  323.   }
  324.   srv = CERT_FinishExtensions(extHandle);
  325.   if (srv != SECSuccess) {
  326.     rv = ERROR_ENDING_EXTENSIONS;
  327.     goto loser;
  328.   }
  329.   return NO_ERROR;
  330.  loser:
  331.   return rv;
  332. }
  333. void
  334. writeOutItem(const char *filePath, SECItem *der)
  335. {
  336.   PRFileDesc *outfile;
  337.   outfile = PR_Open (filePath,
  338.      PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
  339.      0666);
  340.   PR_Write(outfile, der->data, der->len);
  341.   PR_Close(outfile);
  342. }
  343. ErrorCode
  344. createNewCert(CERTCertificate**issuedCert,CERTCertificateRequest *oldCertReq,
  345.       CRMFCertReqMsg *currReq, CRMFCertRequest *certReq, 
  346.       CERTCertificate *issuerCert, CGIVarTable *varTable)
  347. {
  348.   CERTCertificate *newCert = NULL;
  349.   CERTValidity *validity;
  350.   PRExplodedTime printableTime;
  351.   PRTime now, after;
  352.   ErrorCode rv=NO_ERROR;
  353.   SECKEYPrivateKey *issuerPrivKey;
  354.   SECItem derCert = { 0 };
  355.   SECOidTag signTag;
  356.   SECStatus srv;
  357.   long version;
  358.   now = PR_Now();
  359.   PR_ExplodeTime(now, PR_GMTParameters, &printableTime);
  360.   printableTime.tm_month += 9;
  361.   after = PR_ImplodeTime(&printableTime);
  362.   validity = CERT_CreateValidity(now, after);
  363.   newCert = *issuedCert = 
  364.     CERT_CreateCertificate(rand(), &(issuerCert->subject), validity, 
  365.    oldCertReq);
  366.   if (newCert == NULL) {
  367.     rv = ERROR_CREATING_NEW_CERTIFICATE;
  368.     goto loser;
  369.   }
  370.   rv = addExtensions(newCert, certReq);
  371.   if (rv != NO_ERROR) {
  372.     goto loser;
  373.   }
  374.   issuerPrivKey = PK11_FindKeyByAnyCert(issuerCert, varTable);
  375.   if (issuerPrivKey == NULL) {
  376.     rv = COULD_NOT_FIND_ISSUER_PRIVATE_KEY;
  377.   }
  378.   switch(issuerPrivKey->keyType) {
  379.   case rsaKey:
  380.     signTag = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION;
  381.     break;
  382.   case dsaKey:
  383.     signTag = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST;
  384.     break;
  385.   default:
  386.     rv = UNSUPPORTED_SIGN_OPERATION_FOR_ISSUER;
  387.     goto loser;
  388.   }
  389.   srv = SECOID_SetAlgorithmID(newCert->arena, &newCert->signature, 
  390.       signTag, 0);
  391.   if (srv != SECSuccess) {
  392.     rv = ERROR_SETTING_SIGN_ALG;
  393.     goto loser;
  394.   }
  395.   srv = CRMF_CertRequestGetCertTemplateVersion(certReq, &version);
  396.   if (srv != SECSuccess) {
  397.     /* No version included in the request */
  398.     *(newCert->version.data) = SEC_CERTIFICATE_VERSION_3;
  399.   } else {
  400.     SECITEM_FreeItem(&newCert->version, PR_FALSE);
  401.     SEC_ASN1EncodeInteger(newCert->arena, &newCert->version, version);
  402.   }
  403.   SEC_ASN1EncodeItem(newCert->arena, &derCert, newCert, 
  404.      CERT_CertificateTemplate);
  405.   if (derCert.data == NULL) {
  406.     rv = ERROR_ENCODING_NEW_CERT;
  407.     goto loser;
  408.   }
  409.   srv = SEC_DerSignData(newCert->arena, &(newCert->derCert), derCert.data,
  410. derCert.len, issuerPrivKey, signTag);
  411.   if (srv != SECSuccess) {
  412.     rv = ERROR_SIGNING_NEW_CERT;
  413.     goto loser;
  414.   }
  415. #ifdef WRITE_OUT_RESPONSE
  416.   writeOutItem("newcert.der", &newCert->derCert);
  417. #endif
  418.   return NO_ERROR;
  419.  loser:
  420.   *issuedCert = NULL;
  421.   if (newCert) {
  422.     CERT_DestroyCertificate(newCert);
  423.   }
  424.   return rv;
  425.      
  426. }
  427. void
  428. formatCMMFResponse(char *nickname, char *base64Response)
  429. {
  430.   char *currLine, *nextLine;
  431.   printf("var retVal = crypto.importUserCertificates("%s",n", nickname);
  432.   currLine = base64Response;
  433.   while (1) {
  434.     nextLine = strchr(currLine, 'n');
  435.     if (nextLine == NULL) {
  436.       /* print out the last line here. */
  437.       printf (""%s",n", currLine);
  438.       break;
  439.     }
  440.     nextLine[0] = '';
  441.     printf(""%s\n"+n", currLine);
  442.     currLine = nextLine+1;
  443.   }
  444.   printf("true);n"
  445.  "if(retVal == '') {n"
  446.  "tdocument.write("<h1>New Certificate Succesfully Imported.</h1>");n"
  447.  "} else {n"
  448.  "tdocument.write("<h2>Unable to import New Certificate</h2>");n"
  449.  "tdocument.write("crypto.importUserCertificates returned <b>");n"
  450.  "tdocument.write(retVal);n"
  451.  "tdocument.write("</b>");n"
  452.  "}n");
  453. }
  454. void
  455. spitOutCMMFResponse(char *nickname, char *base64Response)
  456. {
  457.   spitOutHeaders();
  458.   printf("<html>n<head>n<title>CMMF Resonse Page</title>n</head>nn"
  459.  "<body><h1>CMMF Response Page</h1>n"
  460.  "<script language="JavaScript">n"
  461.  "<!--n");
  462.   formatCMMFResponse(nickname, base64Response);
  463.   printf("// -->n"
  464.  "</script>n</body>n</html>");
  465. }
  466. char*
  467. getNickname(CERTCertificate *cert)
  468. {
  469.   char *nickname;
  470.   if (cert->nickname != NULL) {
  471.     return cert->nickname;
  472.   }
  473.   nickname = CERT_GetCommonName(&cert->subject);
  474.   if (nickname != NULL) {
  475.     return nickname;
  476.   }
  477.   return CERT_NameToAscii(&cert->subject);
  478. }
  479. ErrorCode
  480. createCMMFResponse(CertResponseInfo *issuedCerts, int numCerts, 
  481.    CERTCertificate *issuerCert, char **base64der)
  482. {
  483.  CMMFCertRepContent *certRepContent=NULL;
  484.   ErrorCode rv = NO_ERROR;
  485.   CMMFCertResponse **responses, *currResponse;
  486.   CERTCertList *caList;
  487.   int i;
  488.   SECStatus srv;
  489.   PRArenaPool *poolp;
  490.   SECItem *der;
  491.   certRepContent = CMMF_CreateCertRepContent();
  492.   if (certRepContent == NULL) {
  493.     rv = ERROR_CREATING_CERT_REP_CONTENT;
  494.     goto loser;
  495.   }
  496.   responses = PORT_NewArray(CMMFCertResponse*, numCerts);
  497.   if (responses == NULL) {
  498.     rv = OUT_OF_MEMORY;
  499.     goto loser;
  500.   }
  501.   for (i=0; i<numCerts;i++) {
  502.     responses[i] = currResponse = 
  503.       CMMF_CreateCertResponse(issuedCerts[i].certReqID);
  504.     if (currResponse == NULL) {
  505.       rv = ERROR_CREATING_SINGLE_CERT_RESPONSE;
  506.       goto loser;
  507.     }
  508.     CMMF_CertResponseSetPKIStatusInfoStatus(currResponse, cmmfGranted);
  509.     CMMF_CertResponseSetCertificate(currResponse, issuedCerts[i].cert);
  510.   }
  511.   srv = CMMF_CertRepContentSetCertResponses(certRepContent, responses,
  512.     numCerts);
  513.   if (srv != SECSuccess) {
  514.     rv = ERROR_SETTING_CERT_RESPONSES;
  515.     goto loser;
  516.   }
  517.   caList = CERT_NewCertList();
  518.   if (caList == NULL) {
  519.     rv = ERROR_CREATING_CA_LIST;
  520.     goto loser;
  521.   }
  522.   srv = CERT_AddCertToListTail(caList, issuerCert);
  523.   if (srv != SECSuccess) {
  524.     rv = ERROR_ADDING_ISSUER_TO_CA_LIST;
  525.     goto loser;
  526.   }
  527.   srv = CMMF_CertRepContentSetCAPubs(certRepContent, caList);
  528.   CERT_DestroyCertList(caList);
  529.   poolp = PORT_NewArena(1024);
  530.   der = SEC_ASN1EncodeItem(poolp, NULL, certRepContent, 
  531.    CMMFCertRepContentTemplate);
  532.   if (der == NULL) {
  533.     rv = ERROR_ENCODING_CERT_REP_CONTENT;
  534.     goto loser;
  535.   }
  536. #ifdef WRITE_OUT_RESPONSE
  537.   writeOutItem("CertRepContent.der", der);
  538. #endif
  539.   *base64der = BTOA_DataToAscii(der->data, der->len);
  540.   return NO_ERROR;
  541.  loser:
  542.   return rv;
  543. }
  544. ErrorCode
  545. issueCerts(CertResponseInfo *issuedCerts, int numCerts, 
  546.    CERTCertificate *issuerCert)
  547. {
  548.   ErrorCode rv;
  549.   char *base64Response;
  550.   rv = createCMMFResponse(issuedCerts, numCerts, issuerCert, &base64Response);
  551.   if (rv != NO_ERROR) {
  552.     goto loser;
  553.   }
  554.   spitOutCMMFResponse(getNickname(issuedCerts[0].cert),base64Response);
  555.   return NO_ERROR;
  556.  loser:
  557.   return rv;
  558. }
  559. ErrorCode
  560. verifySignature(CGIVarTable *varTable, CRMFCertReqMsg *currReq, 
  561. CRMFCertRequest *certReq, CERTCertificate *newCert)
  562. {
  563.   SECStatus srv;
  564.   ErrorCode rv = NO_ERROR;
  565.   CRMFPOPOSigningKey *signKey   = NULL;
  566.   SECAlgorithmID     *algID     = NULL;
  567.   SECItem            *signature = NULL;
  568.   SECKEYPublicKey    *pubKey    = NULL;
  569.   SECItem            *reqDER    = NULL;
  570.   srv = CRMF_CertReqMsgGetPOPOSigningKey(currReq, &signKey);
  571.   if (srv != SECSuccess || signKey == NULL) {
  572.     rv = ERROR_RETRIEVING_POP_SIGN_KEY;
  573.     goto loser;
  574.   }
  575.   algID = CRMF_POPOSigningKeyGetAlgID(signKey);
  576.   if (algID == NULL) {
  577.     rv = ERROR_RETRIEVING_ALG_ID_FROM_SIGN_KEY;
  578.     goto loser;
  579.   }
  580.   signature = CRMF_POPOSigningKeyGetSignature(signKey);
  581.   if (signature == NULL) {
  582.     rv = ERROR_RETRIEVING_SIGNATURE_FROM_POP_SIGN_KEY;
  583.     goto loser;
  584.   }
  585.   /* Make the length the number of bytes instead of bits */
  586.   signature->len = (signature->len+7)/8;
  587.   pubKey = CERT_ExtractPublicKey(newCert);
  588.   if (pubKey == NULL) {
  589.     rv = ERROR_RETRIEVING_PUB_KEY_FROM_NEW_CERT;
  590.     goto loser;
  591.   }
  592.   reqDER = SEC_ASN1EncodeItem(NULL, NULL, certReq, CRMFCertRequestTemplate);
  593.   if (reqDER == NULL) {
  594.     rv = ERROR_ENCODING_CERT_REQ_FOR_POP;
  595.     goto loser;
  596.   }
  597.   srv = VFY_VerifyData(reqDER->data, reqDER->len, pubKey, signature,
  598.        SECOID_FindOIDTag(&algID->algorithm), varTable);
  599.   if (srv != SECSuccess) {
  600.     rv = ERROR_VERIFYING_SIGNATURE_POP;
  601.     goto loser;
  602.   }
  603.   /* Fall thru in successfull case. */
  604.  loser:
  605.   if (pubKey != NULL) {
  606.     SECKEY_DestroyPublicKey(pubKey);
  607.   }
  608.   if (reqDER != NULL) {
  609.     SECITEM_FreeItem(reqDER, PR_TRUE);
  610.   }
  611.   if (signature != NULL) {
  612.     SECITEM_FreeItem(signature, PR_TRUE);
  613.   }
  614.   if (algID != NULL) {
  615.     SECOID_DestroyAlgorithmID(algID, PR_TRUE);
  616.   }
  617.   if (signKey != NULL) {
  618.     CRMF_DestroyPOPOSigningKey(signKey);
  619.   }  
  620.   return rv;
  621. }
  622. ErrorCode
  623. doChallengeResponse(CGIVarTable *varTable, CRMFCertReqMsg *currReq, 
  624.     CRMFCertRequest *certReq, CERTCertificate *newCert,
  625.     ChallengeCreationInfo *challs, int *numChall)
  626. {
  627.   CRMFPOPOPrivKey *privKey = NULL;
  628.   CRMFPOPOPrivKeyChoice privKeyChoice;
  629.   SECStatus srv;
  630.   ErrorCode rv = NO_ERROR;
  631.  
  632.   srv = CRMF_CertReqMsgGetPOPKeyEncipherment(currReq, &privKey);
  633.   if (srv != SECSuccess || privKey == NULL) {
  634.     rv = ERROR_GETTING_KEY_ENCIPHERMENT;
  635.     goto loser;
  636.   } 
  637.   privKeyChoice = CRMF_POPOPrivKeyGetChoice(privKey);
  638.   CRMF_DestroyPOPOPrivKey(privKey);
  639.   switch (privKeyChoice) {
  640.   case crmfSubsequentMessage:
  641.     challs = &challs[*numChall];
  642.     challs->random = rand();
  643.     challs->pubKey = CERT_ExtractPublicKey(newCert);
  644.     if (challs->pubKey == NULL) {
  645.       rv = ERROR_RETRIEVING_PUB_KEY_FOR_CHALL;
  646.       goto loser;
  647.     }
  648.     (*numChall)++;
  649.     rv = DO_CHALLENGE_RESPONSE;
  650.     break;
  651.   case crmfThisMessage:
  652.     /* There'd better be a PKIArchiveControl in this message */
  653.     if (!CRMF_CertRequestIsControlPresent(certReq, 
  654.   crmfPKIArchiveOptionsControl)) {
  655.       rv = ERROR_NO_POP_FOR_PRIVKEY;
  656.       goto loser;
  657.     }
  658.     break;
  659.   default:
  660.     rv = ERROR_UNSUPPORTED_POPOPRIVKEY_TYPE;
  661.     goto loser;
  662.   }
  663. loser:
  664.   return rv;
  665. }
  666. ErrorCode
  667. doProofOfPossession(CGIVarTable *varTable, CRMFCertReqMsg *currReq, 
  668.     CRMFCertRequest *certReq, CERTCertificate *newCert,
  669.     ChallengeCreationInfo *challs, int *numChall)
  670. {
  671.   CRMFPOPChoice popChoice;
  672.   ErrorCode rv = NO_ERROR;
  673.   popChoice = CRMF_CertReqMsgGetPOPType(currReq);
  674.   if (popChoice == crmfNoPOPChoice) {
  675.     rv = NO_POP_FOR_REQUEST;
  676.     goto loser;
  677.   }
  678.   switch (popChoice) {
  679.   case crmfSignature:
  680.     rv = verifySignature(varTable, currReq, certReq, newCert);
  681.     break;
  682.   case crmfKeyEncipherment:
  683.     rv = doChallengeResponse(varTable, currReq, certReq, newCert,
  684.      challs, numChall);
  685.     break;
  686.   case crmfRAVerified:
  687.   case crmfKeyAgreement:
  688.   default:
  689.     rv = UNSUPPORTED_POP;
  690.     goto loser;
  691.   }
  692.  loser:
  693.   return rv;
  694. }
  695. void
  696. convertB64ToJS(char *base64)
  697. {
  698.   int i;
  699.   for (i=0; base64[i] != ''; i++) {
  700.     if (base64[i] == 'n') {
  701.       printf ("\n");
  702.     }else {
  703.       printf ("%c", base64[i]);
  704.     }
  705.   }
  706. }
  707. void
  708. formatChallenge(char *chall64, char *certRepContentDER,
  709.  ChallengeCreationInfo *challInfo, int numChalls)
  710. {
  711.   printf ("function respondToChallenge() {n"
  712.   "  var chalForm = document.chalForm;nn"
  713.   "  chalForm.CertRepContent.value = '");
  714.   convertB64ToJS(certRepContentDER);
  715.   printf ("';n"
  716.   "  chalForm.ChallResponse.value = crypto.popChallengeResponse('");
  717.   convertB64ToJS(chall64);
  718.   printf("');n"
  719.  "  chalForm.submit();n"
  720.  "}n");
  721. }
  722. void
  723. spitOutChallenge(char *chall64, char *certRepContentDER,
  724.  ChallengeCreationInfo *challInfo, int numChalls,
  725.  char *nickname)
  726. {
  727.   int i;
  728.   spitOutHeaders();
  729.   printf("<html>n"
  730.  "<head>n"
  731.  "<title>Challenge Page</title>n"
  732.  "<script language="JavaScript">n"
  733.  "<!--n");
  734.   /* The JavaScript function actually gets defined within
  735.    * this function call
  736.    */
  737.   formatChallenge(chall64, certRepContentDER, challInfo, numChalls);
  738.   printf("// -->n"
  739.  "</script>n"
  740.  "</head>n"
  741.  "<body onLoad='respondToChallenge()'>n"
  742.  "<h1>Cartman is now responding to the Challenge "
  743.  "presented by the CGI</h1>n"
  744.  "<form action='crmfcgi' method='post' name='chalForm'>n"
  745.  "<input type='hidden' name=CertRepContent value=''>n"
  746.  "<input type='hidden' name=ChallResponse value=''>n");
  747.   for (i=0;i<numChalls; i++) {
  748.     printf("<input type='hidden' name='chal%d' value='%d'>n",
  749.    i+1, challInfo[i].random);
  750.   }
  751.   printf("<input type='hidden' name='nickname' value='%s'>n", nickname);
  752.   printf("</form>n</body>n</html>");
  753. }
  754. ErrorCode
  755. issueChallenge(CertResponseInfo *issuedCerts, int numCerts, 
  756.        ChallengeCreationInfo *challInfo, int numChalls,
  757.        CERTCertificate *issuer, CGIVarTable *varTable)
  758. {
  759.   ErrorCode rv = NO_ERROR;
  760.   CMMFPOPODecKeyChallContent *chalContent = NULL;
  761.   int i;
  762.   SECStatus srv;
  763.   PRArenaPool *poolp;
  764.   CERTGeneralName *genName;
  765.   SECItem *challDER = NULL;
  766.   char *chall64, *certRepContentDER;
  767.   rv = createCMMFResponse(issuedCerts, numCerts, issuer, 
  768.   &certRepContentDER);
  769.   if (rv != NO_ERROR) {
  770.     goto loser;
  771.   }
  772.   chalContent = CMMF_CreatePOPODecKeyChallContent();
  773.   if (chalContent == NULL) {
  774.     rv = ERROR_CREATING_EMPTY_CHAL_CONTENT;
  775.     goto loser;
  776.   }
  777.   poolp = PORT_NewArena(1024);
  778.   if (poolp == NULL) {
  779.     rv = OUT_OF_MEMORY;
  780.     goto loser;
  781.   }
  782.   genName = CERT_GetCertificateNames(issuer, poolp);
  783.   if (genName == NULL) {
  784.     rv = ERROR_EXTRACTING_GEN_NAME_FROM_ISSUER;
  785.     goto loser;
  786.   }
  787.   for (i=0;i<numChalls;i++) {
  788.     srv = CMMF_POPODecKeyChallContentSetNextChallenge(chalContent,
  789.       challInfo[i].random,
  790.       genName,
  791.       challInfo[i].pubKey,
  792.       varTable);
  793.     SECKEY_DestroyPublicKey(challInfo[i].pubKey);
  794.     if (srv != SECSuccess) {
  795.       rv = ERROR_SETTING_CHALLENGE;
  796.       goto loser;
  797.     }
  798.   }
  799.   challDER = SEC_ASN1EncodeItem(NULL, NULL, chalContent, 
  800. CMMFPOPODecKeyChallContentTemplate);
  801.   if (challDER == NULL) {
  802.     rv = ERROR_ENCODING_CHALL;
  803.     goto loser;
  804.   }
  805.   chall64 = BTOA_DataToAscii(challDER->data, challDER->len);
  806.   SECITEM_FreeItem(challDER, PR_TRUE);
  807.   if (chall64 == NULL) {
  808.     rv = ERROR_CONVERTING_CHALL_TO_BASE64;
  809.     goto loser;
  810.   }
  811.   spitOutChallenge(chall64, certRepContentDER, challInfo, numChalls,
  812.    getNickname(issuedCerts[0].cert));
  813.  loser:
  814.   return rv;
  815. }
  816. ErrorCode
  817. processRequest(CGIVarTable *varTable)
  818. {
  819.   CERTCertDBHandle *certdb;
  820.   SECKEYKeyDBHandle *keydb;
  821.   CRMFCertReqMessages *certReqs = NULL;
  822.   const char *crmfReq;
  823.   const char *caNickname;
  824.   CERTCertificate *caCert = NULL;
  825.   CertResponseInfo *issuedCerts = NULL;
  826.   CERTSubjectPublicKeyInfo spki = { 0 };
  827.   ErrorCode rv=NO_ERROR;
  828.   PRBool doChallengeResponse = PR_FALSE;
  829.   SECItem der = { 0 };
  830.   SECStatus srv;
  831.   CERTCertificateRequest oldCertReq = { 0 };
  832.   CRMFCertReqMsg **reqMsgs = NULL,*currReq = NULL;
  833.   CRMFCertRequest **reqs = NULL, *certReq = NULL;
  834.   CERTName         subject = { 0 };
  835.   int numReqs,i;
  836.   ChallengeCreationInfo *challInfo=NULL;
  837.   int numChalls = 0;
  838.   certdb = CERT_GetDefaultCertDB();
  839.   keydb = SECKEY_GetDefaultKeyDB();
  840.   crmfReq = CGITableFindValue(varTable, "CRMFRequest");
  841.   if (crmfReq == NULL) {
  842.     rv = CGI_VAR_MISSING;
  843.     missingVar = "CRMFRequest";
  844.     goto loser;
  845.   }
  846.   caNickname = CGITableFindValue(varTable, "CANickname");
  847.   if (caNickname == NULL) {
  848.     rv = CGI_VAR_MISSING;
  849.     missingVar = "CANickname";
  850.     goto loser;
  851.   }
  852.   caCert = CERT_FindCertByNickname(certdb, caNickname);
  853.   if (caCert == NULL) {
  854.     rv = COULD_NOT_FIND_CA;
  855.     goto loser;
  856.   }
  857.   srv = ATOB_ConvertAsciiToItem(&der, crmfReq);
  858.   if (srv != SECSuccess) {
  859.     rv = BAD_ASCII_FOR_REQ;
  860.     goto loser;
  861.   }
  862.   certReqs = CRMF_CreateCertReqMessagesFromDER(der.data, der.len);
  863.   SECITEM_FreeItem(&der, PR_FALSE);
  864.   if (certReqs == NULL) {
  865.     rv = COULD_NOT_DECODE_REQS;
  866.     goto loser;
  867.   }
  868.   numReqs = CRMF_CertReqMessagesGetNumMessages(certReqs);
  869.   issuedCerts = PORT_ZNewArray(CertResponseInfo, numReqs);
  870.   challInfo   = PORT_ZNewArray(ChallengeCreationInfo, numReqs);
  871.   if (issuedCerts == NULL || challInfo == NULL) {
  872.     rv = OUT_OF_MEMORY;
  873.     goto loser;
  874.   }
  875.   reqMsgs = PORT_ZNewArray(CRMFCertReqMsg*,   numReqs);
  876.   reqs    = PORT_ZNewArray(CRMFCertRequest*, numReqs);
  877.   if (reqMsgs == NULL || reqs == NULL) {
  878.     rv =   OUT_OF_MEMORY;
  879.     goto loser;
  880.   }
  881.   for (i=0; i<numReqs; i++) {
  882.     currReq = reqMsgs[i] = 
  883.       CRMF_CertReqMessagesGetCertReqMsgAtIndex(certReqs, i);
  884.     if (currReq == NULL) {
  885.       rv = ERROR_RETRIEVING_REQUEST_MSG;
  886.       goto loser;
  887.     }
  888.     certReq = reqs[i] = CRMF_CertReqMsgGetCertRequest(currReq);
  889.     if (certReq == NULL) {
  890.       rv = ERROR_RETRIEVING_CERT_REQUEST;
  891.       goto loser;
  892.     }
  893.     srv = CRMF_CertRequestGetCertTemplateSubject(certReq, &subject);
  894.     if (srv != SECSuccess) {
  895.       rv = ERROR_RETRIEVING_SUBJECT_FROM_REQ;
  896.       goto loser;
  897.     }
  898.     srv = CRMF_CertRequestGetCertTemplatePublicKey(certReq, &spki);
  899.     if (srv != SECSuccess) {
  900.       rv = ERROR_RETRIEVING_PUBLIC_KEY_FROM_REQ;
  901.       goto loser;
  902.     }
  903.     rv = initOldCertReq(&oldCertReq, &subject, &spki);
  904.     if (rv != NO_ERROR) {
  905.       goto loser;
  906.     }
  907.     rv = createNewCert(&issuedCerts[i].cert, &oldCertReq, currReq, certReq, 
  908.        caCert, varTable);
  909.     if (rv != NO_ERROR) {
  910.       goto loser;
  911.     }
  912.     rv = doProofOfPossession(varTable, currReq, certReq, issuedCerts[i].cert,
  913.      challInfo, &numChalls);
  914.     if (rv != NO_ERROR) {
  915.       if (rv == DO_CHALLENGE_RESPONSE) {
  916. doChallengeResponse = PR_TRUE;
  917.       } else {
  918. goto loser;
  919.       }
  920.     }
  921.     CRMF_CertReqMsgGetID(currReq, &issuedCerts[i].certReqID);
  922.     CRMF_DestroyCertReqMsg(currReq);
  923.     CRMF_DestroyCertRequest(certReq);
  924.   }
  925.   if (doChallengeResponse) {
  926.     rv = issueChallenge(issuedCerts, numReqs, challInfo, numChalls, caCert,
  927. varTable);
  928.   } else {
  929.     rv = issueCerts(issuedCerts, numReqs, caCert);
  930.   }
  931.  loser:
  932.   if (certReqs != NULL) {
  933.     CRMF_DestroyCertReqMessages(certReqs);
  934.   }
  935.   return rv;
  936. }
  937. ErrorCode
  938. processChallengeResponse(CGIVarTable *varTable, const char *certRepContent)
  939. {
  940.   SECItem binDER = { 0 };
  941.   SECStatus srv;
  942.   ErrorCode rv = NO_ERROR;
  943.   const char *clientResponse;
  944.   const char *formChalValue;
  945.   const char *nickname;
  946.   CMMFPOPODecKeyRespContent *respContent = NULL;
  947.   int numResponses,i;
  948.   long curResponse, expectedResponse;
  949.   char cgiChalVar[10];
  950. #ifdef WRITE_OUT_RESPONSE
  951.   SECItem certRepBinDER = { 0 };
  952.   ATOB_ConvertAsciiToItem(&certRepBinDER, certRepContent);
  953.   writeOutItem("challCertRepContent.der", &certRepBinDER);
  954.   PORT_Free(certRepBinDER.data);
  955. #endif  
  956.   clientResponse = CGITableFindValue(varTable, "ChallResponse");
  957.   if (clientResponse == NULL) {
  958.     rv =   REQ_CGI_VAR_NOT_PRESENT;
  959.     missingVar = "ChallResponse";
  960.     goto loser;
  961.   }
  962.   srv = ATOB_ConvertAsciiToItem(&binDER, clientResponse);
  963.   if (srv != SECSuccess) {
  964.     rv = ERROR_CONVERTING_RESP_FROM_CHALL_TO_BIN;
  965.     goto loser;
  966.   }
  967.   respContent = CMMF_CreatePOPODecKeyRespContentFromDER(binDER.data,
  968. binDER.len);
  969.   SECITEM_FreeItem(&binDER, PR_FALSE);
  970.   binDER.data = NULL;
  971.   if (respContent == NULL) {
  972.     rv = ERROR_CREATING_KEY_RESP_FROM_DER;
  973.     goto loser;
  974.   }
  975.   numResponses = CMMF_POPODecKeyRespContentGetNumResponses(respContent);
  976.   for (i=0;i<numResponses;i++){
  977.     srv = CMMF_POPODecKeyRespContentGetResponse(respContent,i,&curResponse);
  978.     if (srv != SECSuccess) {
  979.       rv = ERROR_RETRIEVING_CLIENT_RESPONSE_TO_CHALLENGE;
  980.       goto loser;
  981.     }
  982.     sprintf(cgiChalVar, "chal%d", i+1);
  983.     formChalValue = CGITableFindValue(varTable, cgiChalVar);
  984.     if (formChalValue == NULL) {
  985.       rv = REQ_CGI_VAR_NOT_PRESENT;
  986.       missingVar = strdup(cgiChalVar);
  987.       goto loser;
  988.     }
  989.     sscanf(formChalValue, "%ld", &expectedResponse);
  990.     if (expectedResponse != curResponse) {
  991.       rv = ERROR_RETURNED_CHALL_NOT_VALUE_EXPECTED;
  992.       goto loser;
  993.     }
  994.   }
  995.   nickname = CGITableFindValue(varTable, "nickname");
  996.   if (nickname == NULL) {
  997.     rv = REQ_CGI_VAR_NOT_PRESENT;
  998.     missingVar = "nickname";
  999.     goto loser;
  1000.   }
  1001.   spitOutCMMFResponse(nickname, certRepContent);
  1002.  loser:
  1003.   if (respContent != NULL) {
  1004.     CMMF_DestroyPOPODecKeyRespContent(respContent);
  1005.   }
  1006.   return rv;
  1007. }
  1008. int
  1009. main()
  1010. {
  1011.   char *form_output = NULL;
  1012.   int   form_output_len, form_output_used;
  1013.   CGIVarTable varTable = { 0 };
  1014.   ErrorCode errNum = 0;
  1015.   char *certRepContent;
  1016. #ifdef ATTACH_CGI
  1017.   /* Put an ifinite loop in here so I can attach to 
  1018.    * the process after the process is spun off
  1019.    */
  1020.   { int stupid = 1;
  1021.     while (stupid);
  1022.   }
  1023. #endif
  1024.   form_output_used = 0;
  1025.   srand(time(NULL));
  1026.   while (feof(stdin) == 0) {
  1027.     if (form_output == NULL) {
  1028.       form_output = PORT_NewArray(char, DEFAULT_ALLOC_SIZE+1);
  1029.       form_output_len  = DEFAULT_ALLOC_SIZE;
  1030.     } else if ((form_output_used + DEFAULT_ALLOC_SIZE) >= form_output_len) {
  1031.       form_output_len += DEFAULT_ALLOC_SIZE;
  1032.       form_output = PORT_Realloc(form_output, form_output_len+1);
  1033.     }
  1034.     form_output_used += fread(&form_output[form_output_used], sizeof(char), 
  1035.       DEFAULT_ALLOC_SIZE, stdin);
  1036.   }
  1037.   ParseInputVariables(&varTable, form_output);
  1038.   certRepContent = CGITableFindValue(&varTable, "CertRepContent");
  1039.   if (certRepContent == NULL) {
  1040.     errNum = initNSS(&varTable);
  1041.     if (errNum != 0) {
  1042.       goto loser;
  1043.     }
  1044.     errNum = processRequest(&varTable);
  1045.   } else {
  1046.     errNum = processChallengeResponse(&varTable, certRepContent);
  1047.   }
  1048.   if (errNum != NO_ERROR) {
  1049.     goto loser;
  1050.   }
  1051.   goto done;
  1052. loser:
  1053.   dumpErrorMessage(errNum);
  1054. done:
  1055.   free (form_output);
  1056.   return 0;
  1057. }