security/nss/cmd/crmf-cgi/crmfcgi.c

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

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

mercurial