michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "seccomon.h" michael@0: #include "nss.h" michael@0: #include "key.h" michael@0: #include "cert.h" michael@0: #include "pk11func.h" michael@0: #include "secmod.h" michael@0: #include "cmmf.h" michael@0: #include "crmf.h" michael@0: #include "base64.h" michael@0: #include "secasn1.h" michael@0: #include "cryptohi.h" michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #define DEFAULT_ALLOC_SIZE 200 michael@0: #define DEFAULT_CGI_VARS 20 michael@0: michael@0: typedef struct CGIVariableStr { michael@0: char *name; michael@0: char *value; michael@0: } CGIVariable; michael@0: michael@0: typedef struct CGIVarTableStr { michael@0: CGIVariable **variables; michael@0: int numVars; michael@0: int numAlloc; michael@0: } CGIVarTable; michael@0: michael@0: typedef struct CertResponseInfoStr { michael@0: CERTCertificate *cert; michael@0: long certReqID; michael@0: } CertResponseInfo; michael@0: michael@0: typedef struct ChallengeCreationInfoStr { michael@0: long random; michael@0: SECKEYPublicKey *pubKey; michael@0: } ChallengeCreationInfo; michael@0: michael@0: char *missingVar = NULL; michael@0: michael@0: /* michael@0: * Error values. michael@0: */ michael@0: typedef enum { michael@0: NO_ERROR = 0, michael@0: NSS_INIT_FAILED, michael@0: AUTH_FAILED, michael@0: REQ_CGI_VAR_NOT_PRESENT, michael@0: CRMF_REQ_NOT_PRESENT, michael@0: BAD_ASCII_FOR_REQ, michael@0: CGI_VAR_MISSING, michael@0: COULD_NOT_FIND_CA, michael@0: COULD_NOT_DECODE_REQS, michael@0: OUT_OF_MEMORY, michael@0: ERROR_RETRIEVING_REQUEST_MSG, michael@0: ERROR_RETRIEVING_CERT_REQUEST, michael@0: ERROR_RETRIEVING_SUBJECT_FROM_REQ, michael@0: ERROR_RETRIEVING_PUBLIC_KEY_FROM_REQ, michael@0: ERROR_CREATING_NEW_CERTIFICATE, michael@0: COULD_NOT_START_EXTENSIONS, michael@0: ERROR_RETRIEVING_EXT_FROM_REQ, michael@0: ERROR_ADDING_EXT_TO_CERT, michael@0: ERROR_ENDING_EXTENSIONS, michael@0: COULD_NOT_FIND_ISSUER_PRIVATE_KEY, michael@0: UNSUPPORTED_SIGN_OPERATION_FOR_ISSUER, michael@0: ERROR_SETTING_SIGN_ALG, michael@0: ERROR_ENCODING_NEW_CERT, michael@0: ERROR_SIGNING_NEW_CERT, michael@0: ERROR_CREATING_CERT_REP_CONTENT, michael@0: ERROR_CREATING_SINGLE_CERT_RESPONSE, michael@0: ERROR_SETTING_CERT_RESPONSES, michael@0: ERROR_CREATING_CA_LIST, michael@0: ERROR_ADDING_ISSUER_TO_CA_LIST, michael@0: ERROR_ENCODING_CERT_REP_CONTENT, michael@0: NO_POP_FOR_REQUEST, michael@0: UNSUPPORTED_POP, michael@0: ERROR_RETRIEVING_POP_SIGN_KEY, michael@0: ERROR_RETRIEVING_ALG_ID_FROM_SIGN_KEY, michael@0: ERROR_RETRIEVING_SIGNATURE_FROM_POP_SIGN_KEY, michael@0: DO_CHALLENGE_RESPONSE, michael@0: ERROR_RETRIEVING_PUB_KEY_FROM_NEW_CERT, michael@0: ERROR_ENCODING_CERT_REQ_FOR_POP, michael@0: ERROR_VERIFYING_SIGNATURE_POP, michael@0: ERROR_RETRIEVING_PUB_KEY_FOR_CHALL, michael@0: ERROR_CREATING_EMPTY_CHAL_CONTENT, michael@0: ERROR_EXTRACTING_GEN_NAME_FROM_ISSUER, michael@0: ERROR_SETTING_CHALLENGE, michael@0: ERROR_ENCODING_CHALL, michael@0: ERROR_CONVERTING_CHALL_TO_BASE64, michael@0: ERROR_CONVERTING_RESP_FROM_CHALL_TO_BIN, michael@0: ERROR_CREATING_KEY_RESP_FROM_DER, michael@0: ERROR_RETRIEVING_CLIENT_RESPONSE_TO_CHALLENGE, michael@0: ERROR_RETURNED_CHALL_NOT_VALUE_EXPECTED, michael@0: ERROR_GETTING_KEY_ENCIPHERMENT, michael@0: ERROR_NO_POP_FOR_PRIVKEY, michael@0: ERROR_UNSUPPORTED_POPOPRIVKEY_TYPE michael@0: } ErrorCode; michael@0: michael@0: const char * michael@0: CGITableFindValue(CGIVarTable *varTable, const char *key); michael@0: michael@0: void michael@0: spitOutHeaders(void) michael@0: { michael@0: printf("Content-type: text/html\n\n"); michael@0: } michael@0: michael@0: void michael@0: dumpRequest(CGIVarTable *varTable) michael@0: { michael@0: int i; michael@0: CGIVariable *var; michael@0: michael@0: printf ("\n"); michael@0: printf ("" michael@0: "\n"); michael@0: for (i=0; inumVars; i++) { michael@0: var = varTable->variables[i]; michael@0: printf ("\n", michael@0: var->name, var->value); michael@0: } michael@0: printf("
Variable Name
Value
%s
%s
\n"); michael@0: } michael@0: michael@0: void michael@0: echo_request(CGIVarTable *varTable) michael@0: { michael@0: spitOutHeaders(); michael@0: printf("CGI Echo Page\n" michael@0: "

Got the following request

\n"); michael@0: dumpRequest(varTable); michael@0: printf(""); michael@0: } michael@0: michael@0: void michael@0: processVariable(CGIVariable *var) michael@0: { michael@0: char *plusSign, *percentSign; michael@0: michael@0: /*First look for all of the '+' and convert them to spaces */ michael@0: plusSign = var->value; michael@0: while ((plusSign=strchr(plusSign, '+')) != NULL) { michael@0: *plusSign = ' '; michael@0: } michael@0: percentSign = var->value; michael@0: while ((percentSign=strchr(percentSign, '%')) != NULL) { michael@0: char string[3]; michael@0: int value; michael@0: michael@0: string[0] = percentSign[1]; michael@0: string[1] = percentSign[2]; michael@0: string[2] = '\0'; michael@0: michael@0: sscanf(string,"%x", &value); michael@0: *percentSign = (char)value; michael@0: memmove(&percentSign[1], &percentSign[3], 1+strlen(&percentSign[3])); michael@0: } michael@0: } michael@0: michael@0: char * michael@0: parseNextVariable(CGIVarTable *varTable, char *form_output) michael@0: { michael@0: char *ampersand, *equal; michael@0: CGIVariable *var; michael@0: michael@0: if (varTable->numVars == varTable->numAlloc) { michael@0: CGIVariable **newArr = realloc(varTable->variables, michael@0: (varTable->numAlloc + DEFAULT_CGI_VARS)*sizeof(CGIVariable*)); michael@0: if (newArr == NULL) { michael@0: return NULL; michael@0: } michael@0: varTable->variables = newArr; michael@0: varTable->numAlloc += DEFAULT_CGI_VARS; michael@0: } michael@0: equal = strchr(form_output, '='); michael@0: if (equal == NULL) { michael@0: return NULL; michael@0: } michael@0: ampersand = strchr(equal, '&'); michael@0: if (ampersand == NULL) { michael@0: return NULL; michael@0: } michael@0: equal[0] = '\0'; michael@0: if (ampersand != NULL) { michael@0: ampersand[0] = '\0'; michael@0: } michael@0: var = malloc(sizeof(CGIVariable)); michael@0: var->name = form_output; michael@0: var->value = &equal[1]; michael@0: varTable->variables[varTable->numVars] = var; michael@0: varTable->numVars++; michael@0: processVariable(var); michael@0: return (ampersand != NULL) ? &ersand[1] : NULL; michael@0: } michael@0: michael@0: void michael@0: ParseInputVariables(CGIVarTable *varTable, char *form_output) michael@0: { michael@0: varTable->variables = malloc(sizeof(CGIVariable*)*DEFAULT_CGI_VARS); michael@0: varTable->numVars = 0; michael@0: varTable->numAlloc = DEFAULT_CGI_VARS; michael@0: while (form_output && form_output[0] != '\0') { michael@0: form_output = parseNextVariable(varTable, form_output); michael@0: } michael@0: } michael@0: michael@0: const char * michael@0: CGITableFindValue(CGIVarTable *varTable, const char *key) michael@0: { michael@0: const char *retVal = NULL; michael@0: int i; michael@0: michael@0: for (i=0; inumVars; i++) { michael@0: if (strcmp(varTable->variables[i]->name, key) == 0) { michael@0: retVal = varTable->variables[i]->value; michael@0: break; michael@0: } michael@0: } michael@0: return retVal; michael@0: } michael@0: michael@0: char* michael@0: passwordCallback(PK11SlotInfo *slot, PRBool retry, void *arg) michael@0: { michael@0: const char *passwd; michael@0: if (retry) { michael@0: return NULL; michael@0: } michael@0: passwd = CGITableFindValue((CGIVarTable*)arg, "dbPassword"); michael@0: if (passwd == NULL) { michael@0: return NULL; michael@0: } michael@0: return PORT_Strdup(passwd); michael@0: } michael@0: michael@0: ErrorCode michael@0: initNSS(CGIVarTable *varTable) michael@0: { michael@0: const char *nssDir; michael@0: PK11SlotInfo *keySlot; michael@0: SECStatus rv; michael@0: michael@0: nssDir = CGITableFindValue(varTable,"NSSDirectory"); michael@0: if (nssDir == NULL) { michael@0: missingVar = "NSSDirectory"; michael@0: return REQ_CGI_VAR_NOT_PRESENT; michael@0: } michael@0: rv = NSS_Init(nssDir); michael@0: if (rv != SECSuccess) { michael@0: return NSS_INIT_FAILED; michael@0: } michael@0: PK11_SetPasswordFunc(passwordCallback); michael@0: keySlot = PK11_GetInternalKeySlot(); michael@0: rv = PK11_Authenticate(keySlot, PR_FALSE, varTable); michael@0: PK11_FreeSlot(keySlot); michael@0: if (rv != SECSuccess) { michael@0: return AUTH_FAILED; michael@0: } michael@0: return NO_ERROR; michael@0: } michael@0: michael@0: void michael@0: dumpErrorMessage(ErrorCode errNum) michael@0: { michael@0: spitOutHeaders(); michael@0: printf("Error

Error processing " michael@0: "data

Received the error %d

", errNum); michael@0: if (errNum == REQ_CGI_VAR_NOT_PRESENT) { michael@0: printf ("The missing variable is %s.", missingVar); michael@0: } michael@0: printf ("More useful information here in the future."); michael@0: } michael@0: michael@0: ErrorCode michael@0: initOldCertReq(CERTCertificateRequest *oldCertReq, michael@0: CERTName *subject, CERTSubjectPublicKeyInfo *spki) michael@0: { michael@0: PLArenaPool *poolp; michael@0: michael@0: poolp = oldCertReq->arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: SEC_ASN1EncodeInteger(poolp, &oldCertReq->version, michael@0: SEC_CERTIFICATE_VERSION_3); michael@0: CERT_CopyName(poolp, &oldCertReq->subject, subject); michael@0: SECKEY_CopySubjectPublicKeyInfo(poolp, &oldCertReq->subjectPublicKeyInfo, michael@0: spki); michael@0: oldCertReq->attributes = NULL; michael@0: return NO_ERROR; michael@0: } michael@0: michael@0: ErrorCode michael@0: addExtensions(CERTCertificate *newCert, CRMFCertRequest *certReq) michael@0: { michael@0: int numExtensions, i; michael@0: void *extHandle; michael@0: ErrorCode rv = NO_ERROR; michael@0: CRMFCertExtension *ext; michael@0: SECStatus srv; michael@0: michael@0: numExtensions = CRMF_CertRequestGetNumberOfExtensions(certReq); michael@0: if (numExtensions == 0) { michael@0: /* No extensions to add */ michael@0: return NO_ERROR; michael@0: } michael@0: extHandle = CERT_StartCertExtensions(newCert); michael@0: if (extHandle == NULL) { michael@0: rv = COULD_NOT_START_EXTENSIONS; michael@0: goto loser; michael@0: } michael@0: for (i=0; idata, der->len); michael@0: PR_Close(outfile); michael@0: michael@0: } michael@0: michael@0: ErrorCode michael@0: createNewCert(CERTCertificate**issuedCert,CERTCertificateRequest *oldCertReq, michael@0: CRMFCertReqMsg *currReq, CRMFCertRequest *certReq, michael@0: CERTCertificate *issuerCert, CGIVarTable *varTable) michael@0: { michael@0: CERTCertificate *newCert = NULL; michael@0: CERTValidity *validity; michael@0: PRExplodedTime printableTime; michael@0: PRTime now, after; michael@0: ErrorCode rv=NO_ERROR; michael@0: SECKEYPrivateKey *issuerPrivKey; michael@0: SECItem derCert = { 0 }; michael@0: SECOidTag signTag; michael@0: SECStatus srv; michael@0: long version; michael@0: michael@0: now = PR_Now(); michael@0: PR_ExplodeTime(now, PR_GMTParameters, &printableTime); michael@0: printableTime.tm_month += 9; michael@0: after = PR_ImplodeTime(&printableTime); michael@0: validity = CERT_CreateValidity(now, after); michael@0: newCert = *issuedCert = michael@0: CERT_CreateCertificate(rand(), &(issuerCert->subject), validity, michael@0: oldCertReq); michael@0: if (newCert == NULL) { michael@0: rv = ERROR_CREATING_NEW_CERTIFICATE; michael@0: goto loser; michael@0: } michael@0: rv = addExtensions(newCert, certReq); michael@0: if (rv != NO_ERROR) { michael@0: goto loser; michael@0: } michael@0: issuerPrivKey = PK11_FindKeyByAnyCert(issuerCert, varTable); michael@0: if (issuerPrivKey == NULL) { michael@0: rv = COULD_NOT_FIND_ISSUER_PRIVATE_KEY; michael@0: } michael@0: signTag = SEC_GetSignatureAlgorithmOidTag(issuerPrivatekey->keytype, michael@0: SEC_OID_UNKNOWN); michael@0: if (signTag == SEC_OID_UNKNOWN) { michael@0: rv = UNSUPPORTED_SIGN_OPERATION_FOR_ISSUER; michael@0: goto loser; michael@0: } michael@0: srv = SECOID_SetAlgorithmID(newCert->arena, &newCert->signature, michael@0: signTag, 0); michael@0: if (srv != SECSuccess) { michael@0: rv = ERROR_SETTING_SIGN_ALG; michael@0: goto loser; michael@0: } michael@0: srv = CRMF_CertRequestGetCertTemplateVersion(certReq, &version); michael@0: if (srv != SECSuccess) { michael@0: /* No version included in the request */ michael@0: *(newCert->version.data) = SEC_CERTIFICATE_VERSION_3; michael@0: } else { michael@0: SECITEM_FreeItem(&newCert->version, PR_FALSE); michael@0: SEC_ASN1EncodeInteger(newCert->arena, &newCert->version, version); michael@0: } michael@0: SEC_ASN1EncodeItem(newCert->arena, &derCert, newCert, michael@0: CERT_CertificateTemplate); michael@0: if (derCert.data == NULL) { michael@0: rv = ERROR_ENCODING_NEW_CERT; michael@0: goto loser; michael@0: } michael@0: srv = SEC_DerSignData(newCert->arena, &(newCert->derCert), derCert.data, michael@0: derCert.len, issuerPrivKey, signTag); michael@0: if (srv != SECSuccess) { michael@0: rv = ERROR_SIGNING_NEW_CERT; michael@0: goto loser; michael@0: } michael@0: #ifdef WRITE_OUT_RESPONSE michael@0: writeOutItem("newcert.der", &newCert->derCert); michael@0: #endif michael@0: return NO_ERROR; michael@0: loser: michael@0: *issuedCert = NULL; michael@0: if (newCert) { michael@0: CERT_DestroyCertificate(newCert); michael@0: } michael@0: return rv; michael@0: michael@0: } michael@0: michael@0: void michael@0: formatCMMFResponse(char *nickname, char *base64Response) michael@0: { michael@0: char *currLine, *nextLine; michael@0: michael@0: printf("var retVal = crypto.importUserCertificates(\"%s\",\n", nickname); michael@0: currLine = base64Response; michael@0: while (1) { michael@0: nextLine = strchr(currLine, '\n'); michael@0: if (nextLine == NULL) { michael@0: /* print out the last line here. */ michael@0: printf ("\"%s\",\n", currLine); michael@0: break; michael@0: } michael@0: nextLine[0] = '\0'; michael@0: printf("\"%s\\n\"+\n", currLine); michael@0: currLine = nextLine+1; michael@0: } michael@0: printf("true);\n" michael@0: "if(retVal == '') {\n" michael@0: "\tdocument.write(\"

New Certificate Successfully Imported.

\");\n" michael@0: "} else {\n" michael@0: "\tdocument.write(\"

Unable to import New Certificate

\");\n" michael@0: "\tdocument.write(\"crypto.importUserCertificates returned \");\n" michael@0: "\tdocument.write(retVal);\n" michael@0: "\tdocument.write(\"\");\n" michael@0: "}\n"); michael@0: } michael@0: michael@0: void michael@0: spitOutCMMFResponse(char *nickname, char *base64Response) michael@0: { michael@0: spitOutHeaders(); michael@0: printf("\n\nCMMF Resonse Page\n\n\n" michael@0: "

CMMF Response Page

\n" michael@0: "\n\n"); michael@0: } michael@0: michael@0: char* michael@0: getNickname(CERTCertificate *cert) michael@0: { michael@0: char *nickname; michael@0: michael@0: if (cert->nickname != NULL) { michael@0: return cert->nickname; michael@0: } michael@0: nickname = CERT_GetCommonName(&cert->subject); michael@0: if (nickname != NULL) { michael@0: return nickname; michael@0: } michael@0: return CERT_NameToAscii(&cert->subject); michael@0: } michael@0: michael@0: ErrorCode michael@0: createCMMFResponse(CertResponseInfo *issuedCerts, int numCerts, michael@0: CERTCertificate *issuerCert, char **base64der) michael@0: { michael@0: CMMFCertRepContent *certRepContent=NULL; michael@0: ErrorCode rv = NO_ERROR; michael@0: CMMFCertResponse **responses, *currResponse; michael@0: CERTCertList *caList; michael@0: int i; michael@0: SECStatus srv; michael@0: PLArenaPool *poolp; michael@0: SECItem *der; michael@0: michael@0: certRepContent = CMMF_CreateCertRepContent(); michael@0: if (certRepContent == NULL) { michael@0: rv = ERROR_CREATING_CERT_REP_CONTENT; michael@0: goto loser; michael@0: } michael@0: responses = PORT_NewArray(CMMFCertResponse*, numCerts); michael@0: if (responses == NULL) { michael@0: rv = OUT_OF_MEMORY; michael@0: goto loser; michael@0: } michael@0: for (i=0; idata, der->len); michael@0: return NO_ERROR; michael@0: loser: michael@0: return rv; michael@0: } michael@0: michael@0: ErrorCode michael@0: issueCerts(CertResponseInfo *issuedCerts, int numCerts, michael@0: CERTCertificate *issuerCert) michael@0: { michael@0: ErrorCode rv; michael@0: char *base64Response; michael@0: michael@0: rv = createCMMFResponse(issuedCerts, numCerts, issuerCert, &base64Response); michael@0: if (rv != NO_ERROR) { michael@0: goto loser; michael@0: } michael@0: spitOutCMMFResponse(getNickname(issuedCerts[0].cert),base64Response); michael@0: return NO_ERROR; michael@0: loser: michael@0: return rv; michael@0: } michael@0: michael@0: ErrorCode michael@0: verifySignature(CGIVarTable *varTable, CRMFCertReqMsg *currReq, michael@0: CRMFCertRequest *certReq, CERTCertificate *newCert) michael@0: { michael@0: SECStatus srv; michael@0: ErrorCode rv = NO_ERROR; michael@0: CRMFPOPOSigningKey *signKey = NULL; michael@0: SECAlgorithmID *algID = NULL; michael@0: SECItem *signature = NULL; michael@0: SECKEYPublicKey *pubKey = NULL; michael@0: SECItem *reqDER = NULL; michael@0: michael@0: srv = CRMF_CertReqMsgGetPOPOSigningKey(currReq, &signKey); michael@0: if (srv != SECSuccess || signKey == NULL) { michael@0: rv = ERROR_RETRIEVING_POP_SIGN_KEY; michael@0: goto loser; michael@0: } michael@0: algID = CRMF_POPOSigningKeyGetAlgID(signKey); michael@0: if (algID == NULL) { michael@0: rv = ERROR_RETRIEVING_ALG_ID_FROM_SIGN_KEY; michael@0: goto loser; michael@0: } michael@0: signature = CRMF_POPOSigningKeyGetSignature(signKey); michael@0: if (signature == NULL) { michael@0: rv = ERROR_RETRIEVING_SIGNATURE_FROM_POP_SIGN_KEY; michael@0: goto loser; michael@0: } michael@0: /* Make the length the number of bytes instead of bits */ michael@0: signature->len = (signature->len+7)/8; michael@0: pubKey = CERT_ExtractPublicKey(newCert); michael@0: if (pubKey == NULL) { michael@0: rv = ERROR_RETRIEVING_PUB_KEY_FROM_NEW_CERT; michael@0: goto loser; michael@0: } michael@0: reqDER = SEC_ASN1EncodeItem(NULL, NULL, certReq, CRMFCertRequestTemplate); michael@0: if (reqDER == NULL) { michael@0: rv = ERROR_ENCODING_CERT_REQ_FOR_POP; michael@0: goto loser; michael@0: } michael@0: srv = VFY_VerifyDataWithAlgorithmID(reqDER->data, reqDER->len, pubKey, michael@0: signature, &algID->algorithm, NULL, varTable); michael@0: if (srv != SECSuccess) { michael@0: rv = ERROR_VERIFYING_SIGNATURE_POP; michael@0: goto loser; michael@0: } michael@0: /* Fall thru in successfull case. */ michael@0: loser: michael@0: if (pubKey != NULL) { michael@0: SECKEY_DestroyPublicKey(pubKey); michael@0: } michael@0: if (reqDER != NULL) { michael@0: SECITEM_FreeItem(reqDER, PR_TRUE); michael@0: } michael@0: if (signature != NULL) { michael@0: SECITEM_FreeItem(signature, PR_TRUE); michael@0: } michael@0: if (algID != NULL) { michael@0: SECOID_DestroyAlgorithmID(algID, PR_TRUE); michael@0: } michael@0: if (signKey != NULL) { michael@0: CRMF_DestroyPOPOSigningKey(signKey); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: ErrorCode michael@0: doChallengeResponse(CGIVarTable *varTable, CRMFCertReqMsg *currReq, michael@0: CRMFCertRequest *certReq, CERTCertificate *newCert, michael@0: ChallengeCreationInfo *challs, int *numChall) michael@0: { michael@0: CRMFPOPOPrivKey *privKey = NULL; michael@0: CRMFPOPOPrivKeyChoice privKeyChoice; michael@0: SECStatus srv; michael@0: ErrorCode rv = NO_ERROR; michael@0: michael@0: srv = CRMF_CertReqMsgGetPOPKeyEncipherment(currReq, &privKey); michael@0: if (srv != SECSuccess || privKey == NULL) { michael@0: rv = ERROR_GETTING_KEY_ENCIPHERMENT; michael@0: goto loser; michael@0: } michael@0: privKeyChoice = CRMF_POPOPrivKeyGetChoice(privKey); michael@0: CRMF_DestroyPOPOPrivKey(privKey); michael@0: switch (privKeyChoice) { michael@0: case crmfSubsequentMessage: michael@0: challs = &challs[*numChall]; michael@0: challs->random = rand(); michael@0: challs->pubKey = CERT_ExtractPublicKey(newCert); michael@0: if (challs->pubKey == NULL) { michael@0: rv = ERROR_RETRIEVING_PUB_KEY_FOR_CHALL; michael@0: goto loser; michael@0: } michael@0: (*numChall)++; michael@0: rv = DO_CHALLENGE_RESPONSE; michael@0: break; michael@0: case crmfThisMessage: michael@0: /* There'd better be a PKIArchiveControl in this message */ michael@0: if (!CRMF_CertRequestIsControlPresent(certReq, michael@0: crmfPKIArchiveOptionsControl)) { michael@0: rv = ERROR_NO_POP_FOR_PRIVKEY; michael@0: goto loser; michael@0: } michael@0: break; michael@0: default: michael@0: rv = ERROR_UNSUPPORTED_POPOPRIVKEY_TYPE; michael@0: goto loser; michael@0: } michael@0: loser: michael@0: return rv; michael@0: } michael@0: michael@0: ErrorCode michael@0: doProofOfPossession(CGIVarTable *varTable, CRMFCertReqMsg *currReq, michael@0: CRMFCertRequest *certReq, CERTCertificate *newCert, michael@0: ChallengeCreationInfo *challs, int *numChall) michael@0: { michael@0: CRMFPOPChoice popChoice; michael@0: ErrorCode rv = NO_ERROR; michael@0: michael@0: popChoice = CRMF_CertReqMsgGetPOPType(currReq); michael@0: if (popChoice == crmfNoPOPChoice) { michael@0: rv = NO_POP_FOR_REQUEST; michael@0: goto loser; michael@0: } michael@0: switch (popChoice) { michael@0: case crmfSignature: michael@0: rv = verifySignature(varTable, currReq, certReq, newCert); michael@0: break; michael@0: case crmfKeyEncipherment: michael@0: rv = doChallengeResponse(varTable, currReq, certReq, newCert, michael@0: challs, numChall); michael@0: break; michael@0: case crmfRAVerified: michael@0: case crmfKeyAgreement: michael@0: default: michael@0: rv = UNSUPPORTED_POP; michael@0: goto loser; michael@0: } michael@0: loser: michael@0: return rv; michael@0: } michael@0: michael@0: void michael@0: convertB64ToJS(char *base64) michael@0: { michael@0: int i; michael@0: michael@0: for (i=0; base64[i] != '\0'; i++) { michael@0: if (base64[i] == '\n') { michael@0: printf ("\\n"); michael@0: }else { michael@0: printf ("%c", base64[i]); michael@0: } michael@0: } michael@0: } michael@0: michael@0: void michael@0: formatChallenge(char *chall64, char *certRepContentDER, michael@0: ChallengeCreationInfo *challInfo, int numChalls) michael@0: { michael@0: printf ("function respondToChallenge() {\n" michael@0: " var chalForm = document.chalForm;\n\n" michael@0: " chalForm.CertRepContent.value = '"); michael@0: convertB64ToJS(certRepContentDER); michael@0: printf ("';\n" michael@0: " chalForm.ChallResponse.value = crypto.popChallengeResponse('"); michael@0: convertB64ToJS(chall64); michael@0: printf("');\n" michael@0: " chalForm.submit();\n" michael@0: "}\n"); michael@0: michael@0: } michael@0: michael@0: void michael@0: spitOutChallenge(char *chall64, char *certRepContentDER, michael@0: ChallengeCreationInfo *challInfo, int numChalls, michael@0: char *nickname) michael@0: { michael@0: int i; michael@0: michael@0: spitOutHeaders(); michael@0: printf("\n" michael@0: "\n" michael@0: "Challenge Page\n" michael@0: "\n" michael@0: "\n" michael@0: "\n" michael@0: "

Cartman is now responding to the Challenge " michael@0: "presented by the CGI

\n" michael@0: "
\n" michael@0: "\n" michael@0: "\n"); michael@0: for (i=0;i\n", michael@0: i+1, challInfo[i].random); michael@0: } michael@0: printf("\n", nickname); michael@0: printf("\n\n"); michael@0: } michael@0: michael@0: ErrorCode michael@0: issueChallenge(CertResponseInfo *issuedCerts, int numCerts, michael@0: ChallengeCreationInfo *challInfo, int numChalls, michael@0: CERTCertificate *issuer, CGIVarTable *varTable) michael@0: { michael@0: ErrorCode rv = NO_ERROR; michael@0: CMMFPOPODecKeyChallContent *chalContent = NULL; michael@0: int i; michael@0: SECStatus srv; michael@0: PLArenaPool *poolp; michael@0: CERTGeneralName *genName; michael@0: SECItem *challDER = NULL; michael@0: char *chall64, *certRepContentDER; michael@0: michael@0: rv = createCMMFResponse(issuedCerts, numCerts, issuer, michael@0: &certRepContentDER); michael@0: if (rv != NO_ERROR) { michael@0: goto loser; michael@0: } michael@0: chalContent = CMMF_CreatePOPODecKeyChallContent(); michael@0: if (chalContent == NULL) { michael@0: rv = ERROR_CREATING_EMPTY_CHAL_CONTENT; michael@0: goto loser; michael@0: } michael@0: poolp = PORT_NewArena(1024); michael@0: if (poolp == NULL) { michael@0: rv = OUT_OF_MEMORY; michael@0: goto loser; michael@0: } michael@0: genName = CERT_GetCertificateNames(issuer, poolp); michael@0: if (genName == NULL) { michael@0: rv = ERROR_EXTRACTING_GEN_NAME_FROM_ISSUER; michael@0: goto loser; michael@0: } michael@0: for (i=0;idata, challDER->len); michael@0: SECITEM_FreeItem(challDER, PR_TRUE); michael@0: if (chall64 == NULL) { michael@0: rv = ERROR_CONVERTING_CHALL_TO_BASE64; michael@0: goto loser; michael@0: } michael@0: spitOutChallenge(chall64, certRepContentDER, challInfo, numChalls, michael@0: getNickname(issuedCerts[0].cert)); michael@0: loser: michael@0: return rv; michael@0: } michael@0: michael@0: michael@0: ErrorCode michael@0: processRequest(CGIVarTable *varTable) michael@0: { michael@0: CERTCertDBHandle *certdb; michael@0: SECKEYKeyDBHandle *keydb; michael@0: CRMFCertReqMessages *certReqs = NULL; michael@0: const char *crmfReq; michael@0: const char *caNickname; michael@0: CERTCertificate *caCert = NULL; michael@0: CertResponseInfo *issuedCerts = NULL; michael@0: CERTSubjectPublicKeyInfo spki = { 0 }; michael@0: ErrorCode rv=NO_ERROR; michael@0: PRBool doChallengeResponse = PR_FALSE; michael@0: SECItem der = { 0 }; michael@0: SECStatus srv; michael@0: CERTCertificateRequest oldCertReq = { 0 }; michael@0: CRMFCertReqMsg **reqMsgs = NULL,*currReq = NULL; michael@0: CRMFCertRequest **reqs = NULL, *certReq = NULL; michael@0: CERTName subject = { 0 }; michael@0: int numReqs,i; michael@0: ChallengeCreationInfo *challInfo=NULL; michael@0: int numChalls = 0; michael@0: michael@0: certdb = CERT_GetDefaultCertDB(); michael@0: keydb = SECKEY_GetDefaultKeyDB(); michael@0: crmfReq = CGITableFindValue(varTable, "CRMFRequest"); michael@0: if (crmfReq == NULL) { michael@0: rv = CGI_VAR_MISSING; michael@0: missingVar = "CRMFRequest"; michael@0: goto loser; michael@0: } michael@0: caNickname = CGITableFindValue(varTable, "CANickname"); michael@0: if (caNickname == NULL) { michael@0: rv = CGI_VAR_MISSING; michael@0: missingVar = "CANickname"; michael@0: goto loser; michael@0: } michael@0: caCert = CERT_FindCertByNickname(certdb, caNickname); michael@0: if (caCert == NULL) { michael@0: rv = COULD_NOT_FIND_CA; michael@0: goto loser; michael@0: } michael@0: srv = ATOB_ConvertAsciiToItem(&der, crmfReq); michael@0: if (srv != SECSuccess) { michael@0: rv = BAD_ASCII_FOR_REQ; michael@0: goto loser; michael@0: } michael@0: certReqs = CRMF_CreateCertReqMessagesFromDER(der.data, der.len); michael@0: SECITEM_FreeItem(&der, PR_FALSE); michael@0: if (certReqs == NULL) { michael@0: rv = COULD_NOT_DECODE_REQS; michael@0: goto loser; michael@0: } michael@0: numReqs = CRMF_CertReqMessagesGetNumMessages(certReqs); michael@0: issuedCerts = PORT_ZNewArray(CertResponseInfo, numReqs); michael@0: challInfo = PORT_ZNewArray(ChallengeCreationInfo, numReqs); michael@0: if (issuedCerts == NULL || challInfo == NULL) { michael@0: rv = OUT_OF_MEMORY; michael@0: goto loser; michael@0: } michael@0: reqMsgs = PORT_ZNewArray(CRMFCertReqMsg*, numReqs); michael@0: reqs = PORT_ZNewArray(CRMFCertRequest*, numReqs); michael@0: if (reqMsgs == NULL || reqs == NULL) { michael@0: rv = OUT_OF_MEMORY; michael@0: goto loser; michael@0: } michael@0: for (i=0; i= form_output_len) { michael@0: form_output_len += DEFAULT_ALLOC_SIZE; michael@0: form_output = PORT_Realloc(form_output, form_output_len+1); michael@0: } michael@0: form_output_used += fread(&form_output[form_output_used], sizeof(char), michael@0: DEFAULT_ALLOC_SIZE, stdin); michael@0: } michael@0: ParseInputVariables(&varTable, form_output); michael@0: certRepContent = CGITableFindValue(&varTable, "CertRepContent"); michael@0: if (certRepContent == NULL) { michael@0: errNum = initNSS(&varTable); michael@0: if (errNum != 0) { michael@0: goto loser; michael@0: } michael@0: errNum = processRequest(&varTable); michael@0: } else { michael@0: errNum = processChallengeResponse(&varTable, certRepContent); michael@0: } michael@0: if (errNum != NO_ERROR) { michael@0: goto loser; michael@0: } michael@0: goto done; michael@0: loser: michael@0: dumpErrorMessage(errNum); michael@0: done: michael@0: free (form_output); michael@0: return 0; michael@0: } michael@0: