Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/security/nss/cmd/crmf-cgi/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 32 kB image not shown  

Quelle  crmfcgi.c   Sprache: C

 
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "seccomon.h"
#include "nss.h"
#include "keyhi.h"
#include "cert.h"
#include "pk11func.h"
#include "secmod.h"
#include "cmmf.h"
#include "crmf.h"
#include "base64.h"
#include "secasn1.h"
#include "cryptohi.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#define DEFAULT_ALLOC_SIZE 200
#define DEFAULT_CGI_VARS 20

typedef struct CGIVariableStr {
    char *name;
    char *value;
} CGIVariable;

typedef struct CGIVarTableStr {
    CGIVariable **variables;
    int numVars;
    int numAlloc;
} CGIVarTable;

typedef struct CertResponseInfoStr {
    CERTCertificate *cert;
    long certReqID;
} CertResponseInfo;

typedef struct ChallengeCreationInfoStr {
    long random;
    SECKEYPublicKey *pubKey;
} ChallengeCreationInfo;

char *missingVar = NULL;

/*
 * Error values.
 */

typedef enum {
    NO_ERROR = 0,
    NSS_INIT_FAILED,
    AUTH_FAILED,
    REQ_CGI_VAR_NOT_PRESENT,
    CRMF_REQ_NOT_PRESENT,
    BAD_ASCII_FOR_REQ,
    CGI_VAR_MISSING,
    COULD_NOT_FIND_CA,
    COULD_NOT_DECODE_REQS,
    OUT_OF_MEMORY,
    ERROR_RETRIEVING_REQUEST_MSG,
    ERROR_RETRIEVING_CERT_REQUEST,
    ERROR_RETRIEVING_SUBJECT_FROM_REQ,
    ERROR_RETRIEVING_PUBLIC_KEY_FROM_REQ,
    ERROR_CREATING_NEW_CERTIFICATE,
    COULD_NOT_START_EXTENSIONS,
    ERROR_RETRIEVING_EXT_FROM_REQ,
    ERROR_ADDING_EXT_TO_CERT,
    ERROR_ENDING_EXTENSIONS,
    COULD_NOT_FIND_ISSUER_PRIVATE_KEY,
    UNSUPPORTED_SIGN_OPERATION_FOR_ISSUER,
    ERROR_SETTING_SIGN_ALG,
    ERROR_ENCODING_NEW_CERT,
    ERROR_SIGNING_NEW_CERT,
    ERROR_CREATING_CERT_REP_CONTENT,
    ERROR_CREATING_SINGLE_CERT_RESPONSE,
    ERROR_SETTING_CERT_RESPONSES,
    ERROR_CREATING_CA_LIST,
    ERROR_ADDING_ISSUER_TO_CA_LIST,
    ERROR_ENCODING_CERT_REP_CONTENT,
    NO_POP_FOR_REQUEST,
    UNSUPPORTED_POP,
    ERROR_RETRIEVING_POP_SIGN_KEY,
    ERROR_RETRIEVING_ALG_ID_FROM_SIGN_KEY,
    ERROR_RETRIEVING_SIGNATURE_FROM_POP_SIGN_KEY,
    DO_CHALLENGE_RESPONSE,
    ERROR_RETRIEVING_PUB_KEY_FROM_NEW_CERT,
    ERROR_ENCODING_CERT_REQ_FOR_POP,
    ERROR_VERIFYING_SIGNATURE_POP,
    ERROR_RETRIEVING_PUB_KEY_FOR_CHALL,
    ERROR_CREATING_EMPTY_CHAL_CONTENT,
    ERROR_EXTRACTING_GEN_NAME_FROM_ISSUER,
    ERROR_SETTING_CHALLENGE,
    ERROR_ENCODING_CHALL,
    ERROR_CONVERTING_CHALL_TO_BASE64,
    ERROR_CONVERTING_RESP_FROM_CHALL_TO_BIN,
    ERROR_CREATING_KEY_RESP_FROM_DER,
    ERROR_RETRIEVING_CLIENT_RESPONSE_TO_CHALLENGE,
    ERROR_RETURNED_CHALL_NOT_VALUE_EXPECTED,
    ERROR_GETTING_KEY_ENCIPHERMENT,
    ERROR_NO_POP_FOR_PRIVKEY,
    ERROR_UNSUPPORTED_POPOPRIVKEY_TYPE
} ErrorCode;

const char *
CGITableFindValue(CGIVarTable *varTable, const char *key);

void
spitOutHeaders(void)
{
    printf("Content-type: text/html\n\n");
}

void
dumpRequest(CGIVarTable *varTable)
{
    int i;
    CGIVariable *var;

    printf("100%%\">\n");
    printf(""
           "\n");
    for (i = 0; i < varTable->numVars; i++) {
        var = varTable->variables[i];
        printf("\n",
               var->name, var->value);
    }
    printf("
Variable Name
Value
%s
%s
\n"
);
}

void
echo_request(CGIVarTable *varTable)
{
    spitOutHeaders();
    printf("CGI Echo Page\n"
           "

Got the following request

\n"
);
    dumpRequest(varTable);
    printf("");
}

void
processVariable(CGIVariable *var)
{
    char *plusSign, *percentSign;

    /*First look for all of the '+' and convert them to spaces */
    plusSign = var->value;
    while ((plusSign = strchr(plusSign, '+')) != NULL) {
        *plusSign = ' ';
    }
    percentSign = var->value;
    while ((percentSign = strchr(percentSign, '%')) != NULL) {
        char string[3];
        int value;

        string[0] = percentSign[1];
        string[1] = percentSign[2];
        string[2] = '\0';

        sscanf(string, "%x", &value);
        *percentSign = (char)value;
        memmove(&percentSign[1], &percentSign[3], 1 + strlen(&percentSign[3]));
    }
}

char *
parseNextVariable(CGIVarTable *varTable, char *form_output)
{
    char *ampersand, *equal;
    CGIVariable *var;

    if (varTable->numVars == varTable->numAlloc) {
        CGIVariable **newArr = realloc(varTable->variables,
                                       (varTable->numAlloc + DEFAULT_CGI_VARS) * sizeof(CGIVariable *));
        if (newArr == NULL) {
            return NULL;
        }
        varTable->variables = newArr;
        varTable->numAlloc += DEFAULT_CGI_VARS;
    }
    equal = strchr(form_output, '=');
    if (equal == NULL) {
        return NULL;
    }
    ampersand = strchr(equal, '&');
    if (ampersand == NULL) {
        return NULL;
    }
    equal[0] = '\0';
    if (ampersand != NULL) {
        ampersand[0] = '\0';
    }
    var = malloc(sizeof(CGIVariable));
    var->name = form_output;
    var->value = &equal[1];
    varTable->variables[varTable->numVars] = var;
    varTable->numVars++;
    processVariable(var);
    return (ampersand != NULL) ? &ersand[1] : NULL;
}

void
ParseInputVariables(CGIVarTable *varTable, char *form_output)
{
    varTable->variables = malloc(sizeof(CGIVariable *) * DEFAULT_CGI_VARS);
    varTable->numVars = 0;
    varTable->numAlloc = DEFAULT_CGI_VARS;
    while (form_output && form_output[0] != '\0') {
        form_output = parseNextVariable(varTable, form_output);
    }
}

const char *
CGITableFindValue(CGIVarTable *varTable, const char *key)
{
    const char *retVal = NULL;
    int i;

    for (i = 0; i < varTable->numVars; i++) {
        if (strcmp(varTable->variables[i]->name, key) == 0) {
            retVal = varTable->variables[i]->value;
            break;
        }
    }
    return retVal;
}

char *
passwordCallback(PK11SlotInfo *slot, PRBool retry, void *arg)
{
    const char *passwd;
    if (retry) {
        return NULL;
    }
    passwd = CGITableFindValue((CGIVarTable *)arg, "dbPassword");
    if (passwd == NULL) {
        return NULL;
    }
    return PORT_Strdup(passwd);
}

ErrorCode
initNSS(CGIVarTable *varTable)
{
    const char *nssDir;
    PK11SlotInfo *keySlot;
    SECStatus rv;

    nssDir = CGITableFindValue(varTable, "NSSDirectory");
    if (nssDir == NULL) {
        missingVar = "NSSDirectory";
        return REQ_CGI_VAR_NOT_PRESENT;
    }
    rv = NSS_Init(nssDir);
    if (rv != SECSuccess) {
        return NSS_INIT_FAILED;
    }
    PK11_SetPasswordFunc(passwordCallback);
    keySlot = PK11_GetInternalKeySlot();
    rv = PK11_Authenticate(keySlot, PR_FALSE, varTable);
    PK11_FreeSlot(keySlot);
    if (rv != SECSuccess) {
        return AUTH_FAILED;
    }
    return NO_ERROR;
}

void
dumpErrorMessage(ErrorCode errNum)
{
    spitOutHeaders();
    printf("Error

Error processing "
           "data

Received the error %d

",
           errNum);
    if (errNum == REQ_CGI_VAR_NOT_PRESENT) {
        printf("The missing variable is %s.", missingVar);
    }
    printf("More useful information here in the future.");
}

ErrorCode
initOldCertReq(CERTCertificateRequest *oldCertReq,
               CERTName *subject, CERTSubjectPublicKeyInfo *spki)
{
    PLArenaPool *poolp;

    poolp = oldCertReq->arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    SEC_ASN1EncodeInteger(poolp, &oldCertReq->version,
                          SEC_CERTIFICATE_VERSION_3);
    CERT_CopyName(poolp, &oldCertReq->subject, subject);
    SECKEY_CopySubjectPublicKeyInfo(poolp, &oldCertReq->subjectPublicKeyInfo,
                                    spki);
    oldCertReq->attributes = NULL;
    return NO_ERROR;
}

ErrorCode
addExtensions(CERTCertificate *newCert, CRMFCertRequest *certReq)
{
    int numExtensions, i;
    void *extHandle;
    ErrorCode rv = NO_ERROR;
    CRMFCertExtension *ext;
    SECStatus srv;

    numExtensions = CRMF_CertRequestGetNumberOfExtensions(certReq);
    if (numExtensions == 0) {
        /* No extensions to add */
        return NO_ERROR;
    }
    extHandle = CERT_StartCertExtensions(newCert);
    if (extHandle == NULL) {
        rv = COULD_NOT_START_EXTENSIONS;
        goto loser;
    }
    for (i = 0; i < numExtensions; i++) {
        ext = CRMF_CertRequestGetExtensionAtIndex(certReq, i);
        if (ext == NULL) {
            rv = ERROR_RETRIEVING_EXT_FROM_REQ;
        }
        srv = CERT_AddExtension(extHandle, CRMF_CertExtensionGetOidTag(ext),
                                CRMF_CertExtensionGetValue(ext),
                                CRMF_CertExtensionGetIsCritical(ext), PR_FALSE);
        if (srv != SECSuccess) {
            rv = ERROR_ADDING_EXT_TO_CERT;
        }
    }
    srv = CERT_FinishExtensions(extHandle);
    if (srv != SECSuccess) {
        rv = ERROR_ENDING_EXTENSIONS;
        goto loser;
    }
    return NO_ERROR;
loser:
    return rv;
}

void
writeOutItem(const char *filePath, SECItem *der)
{
    PRFileDesc *outfile;

    outfile = PR_Open(filePath,
                      PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
                      0666);
    PR_Write(outfile, der->data, der->len);
    PR_Close(outfile);
}

ErrorCode
createNewCert(CERTCertificate **issuedCert, CERTCertificateRequest *oldCertReq,
              CRMFCertReqMsg *currReq, CRMFCertRequest *certReq,
              CERTCertificate *issuerCert, CGIVarTable *varTable)
{
    CERTCertificate *newCert = NULL;
    CERTValidity *validity;
    PRExplodedTime printableTime;
    PRTime now, after;
    ErrorCode rv = NO_ERROR;
    SECKEYPrivateKey *issuerPrivKey;
    SECItem derCert = { 0 };
    SECOidTag signTag;
    SECStatus srv;
    long version;

    now = PR_Now();
    PR_ExplodeTime(now, PR_GMTParameters, &printableTime);
    printableTime.tm_month += 9;
    after = PR_ImplodeTime(&printableTime);
    validity = CERT_CreateValidity(now, after);
    newCert = *issuedCert =
        CERT_CreateCertificate(rand(), &(issuerCert->subject), validity,
                               oldCertReq);
    if (newCert == NULL) {
        rv = ERROR_CREATING_NEW_CERTIFICATE;
        goto loser;
    }
    rv = addExtensions(newCert, certReq);
    if (rv != NO_ERROR) {
        goto loser;
    }
    issuerPrivKey = PK11_FindKeyByAnyCert(issuerCert, varTable);
    if (issuerPrivKey == NULL) {
        rv = COULD_NOT_FIND_ISSUER_PRIVATE_KEY;
    }
    signTag = SEC_GetSignatureAlgorithmOidTag(issuerPrivatekey->keytype,
                                              SEC_OID_UNKNOWN);
    if (signTag == SEC_OID_UNKNOWN) {
        rv = UNSUPPORTED_SIGN_OPERATION_FOR_ISSUER;
        goto loser;
    }
    srv = SECOID_SetAlgorithmID(newCert->arena, &newCert->signature,
                                signTag, 0);
    if (srv != SECSuccess) {
        rv = ERROR_SETTING_SIGN_ALG;
        goto loser;
    }
    srv = CRMF_CertRequestGetCertTemplateVersion(certReq, &version);
    if (srv != SECSuccess) {
        /* No version included in the request */
        *(newCert->version.data) = SEC_CERTIFICATE_VERSION_3;
    } else {
        SECITEM_FreeItem(&newCert->version, PR_FALSE);
        SEC_ASN1EncodeInteger(newCert->arena, &newCert->version, version);
    }
    SEC_ASN1EncodeItem(newCert->arena, &derCert, newCert,
                       CERT_CertificateTemplate);
    if (derCert.data == NULL) {
        rv = ERROR_ENCODING_NEW_CERT;
        goto loser;
    }
    srv = SEC_DerSignData(newCert->arena, &(newCert->derCert), derCert.data,
                          derCert.len, issuerPrivKey, signTag);
    if (srv != SECSuccess) {
        rv = ERROR_SIGNING_NEW_CERT;
        goto loser;
    }
#ifdef WRITE_OUT_RESPONSE
    writeOutItem("newcert.der", &newCert->derCert);
#endif
    return NO_ERROR;
loser:
    *issuedCert = NULL;
    if (newCert) {
        CERT_DestroyCertificate(newCert);
    }
    return rv;
}

void
formatCMMFResponse(char *nickname, char *base64Response)
{
    char *currLine, *nextLine;

    printf("var retVal = crypto.importUserCertificates(\"%s\",\n", nickname);
    currLine = base64Response;
    while (1) {
        nextLine = strchr(currLine, '\n');
        if (nextLine == NULL) {
            /* print out the last line here. */
            printf("\"%s\",\n", currLine);
            break;
        }
        nextLine[0] = '\0';
        printf("\"%s\\n\"+\n", currLine);
        currLine = nextLine + 1;
    }
    printf("true);\n"
           "if(retVal == '') {\n"
           "\tdocument.write(\"<h1>New Certificate Successfully Imported.</h1>\");\n"
           "} else {\n"
           "\tdocument.write(\"<h2>Unable to import New Certificate</h2>\");\n"
           "\tdocument.write(\"crypto.importUserCertificates returned <b>\");\n"
           "\tdocument.write(retVal);\n"
           "\tdocument.write(\"</b>\");\n"
           "}\n");
}

void
spitOutCMMFResponse(char *nickname, char *base64Response)
{
    spitOutHeaders();
    printf("\n\nCMMF Resonse Page\n\n\n"
           "

CMMF Response Page

\n"

           "\n\n");
}

char *
getNickname(CERTCertificate *cert)
{
    char *nickname;

    if (cert->nickname != NULL) {
        return cert->nickname;
    }
    nickname = CERT_GetCommonName(&cert->subject);
    if (nickname != NULL) {
        return nickname;
    }
    return CERT_NameToAscii(&cert->subject);
}

ErrorCode
createCMMFResponse(CertResponseInfo *issuedCerts, int numCerts,
                   CERTCertificate *issuerCert, char **base64der)
{
    CMMFCertRepContent *certRepContent = NULL;
    ErrorCode rv = NO_ERROR;
    CMMFCertResponse **responses, *currResponse;
    CERTCertList *caList;
    int i;
    SECStatus srv;
    PLArenaPool *poolp;
    SECItem *der;

    certRepContent = CMMF_CreateCertRepContent();
    if (certRepContent == NULL) {
        rv = ERROR_CREATING_CERT_REP_CONTENT;
        goto loser;
    }
    responses = PORT_NewArray(CMMFCertResponse *, numCerts);
    if (responses == NULL) {
        rv = OUT_OF_MEMORY;
        goto loser;
    }
    for (i = 0; i < numCerts; i++) {
        responses[i] = currResponse =
            CMMF_CreateCertResponse(issuedCerts[i].certReqID);
        if (currResponse == NULL) {
            rv = ERROR_CREATING_SINGLE_CERT_RESPONSE;
            goto loser;
        }
        CMMF_CertResponseSetPKIStatusInfoStatus(currResponse, cmmfGranted);
        CMMF_CertResponseSetCertificate(currResponse, issuedCerts[i].cert);
    }
    srv = CMMF_CertRepContentSetCertResponses(certRepContent, responses,
                                              numCerts);
    if (srv != SECSuccess) {
        rv = ERROR_SETTING_CERT_RESPONSES;
        goto loser;
    }
    caList = CERT_NewCertList();
    if (caList == NULL) {
        rv = ERROR_CREATING_CA_LIST;
        goto loser;
    }
    srv = CERT_AddCertToListTail(caList, issuerCert);
    if (srv != SECSuccess) {
        rv = ERROR_ADDING_ISSUER_TO_CA_LIST;
        goto loser;
    }
    srv = CMMF_CertRepContentSetCAPubs(certRepContent, caList);
    CERT_DestroyCertList(caList);
    poolp = PORT_NewArena(1024);
    der = SEC_ASN1EncodeItem(poolp, NULL, certRepContent,
                             CMMFCertRepContentTemplate);
    if (der == NULL) {
        rv = ERROR_ENCODING_CERT_REP_CONTENT;
        goto loser;
    }
#ifdef WRITE_OUT_RESPONSE
    writeOutItem("CertRepContent.der", der);
#endif
    *base64der = BTOA_DataToAscii(der->data, der->len);
    return NO_ERROR;
loser:
    return rv;
}

ErrorCode
issueCerts(CertResponseInfo *issuedCerts, int numCerts,
           CERTCertificate *issuerCert)
{
    ErrorCode rv;
    char *base64Response;

    rv = createCMMFResponse(issuedCerts, numCerts, issuerCert, &base64Response);
    if (rv != NO_ERROR) {
        goto loser;
    }
    spitOutCMMFResponse(getNickname(issuedCerts[0].cert), base64Response);
    return NO_ERROR;
loser:
    return rv;
}

ErrorCode
verifySignature(CGIVarTable *varTable, CRMFCertReqMsg *currReq,
                CRMFCertRequest *certReq, CERTCertificate *newCert)
{
    SECStatus srv;
    ErrorCode rv = NO_ERROR;
    CRMFPOPOSigningKey *signKey = NULL;
    SECAlgorithmID *algID = NULL;
    SECItem *signature = NULL;
    SECKEYPublicKey *pubKey = NULL;
    SECItem *reqDER = NULL;

    srv = CRMF_CertReqMsgGetPOPOSigningKey(currReq, &signKey);
    if (srv != SECSuccess || signKey == NULL) {
        rv = ERROR_RETRIEVING_POP_SIGN_KEY;
        goto loser;
    }
    algID = CRMF_POPOSigningKeyGetAlgID(signKey);
    if (algID == NULL) {
        rv = ERROR_RETRIEVING_ALG_ID_FROM_SIGN_KEY;
        goto loser;
    }
    signature = CRMF_POPOSigningKeyGetSignature(signKey);
    if (signature == NULL) {
        rv = ERROR_RETRIEVING_SIGNATURE_FROM_POP_SIGN_KEY;
        goto loser;
    }
    /* Make the length the number of bytes instead of bits */
    signature->len = (signature->len + 7) / 8;
    pubKey = CERT_ExtractPublicKey(newCert);
    if (pubKey == NULL) {
        rv = ERROR_RETRIEVING_PUB_KEY_FROM_NEW_CERT;
        goto loser;
    }
    reqDER = SEC_ASN1EncodeItem(NULL, NULL, certReq, CRMFCertRequestTemplate);
    if (reqDER == NULL) {
        rv = ERROR_ENCODING_CERT_REQ_FOR_POP;
        goto loser;
    }
    srv = VFY_VerifyDataWithAlgorithmID(reqDER->data, reqDER->len, pubKey,
                                        signature, &algID->algorithm, NULL, varTable);
    if (srv != SECSuccess) {
        rv = ERROR_VERIFYING_SIGNATURE_POP;
        goto loser;
    }
/* Fall thru in successfull case. */
loser:
    if (pubKey != NULL) {
        SECKEY_DestroyPublicKey(pubKey);
    }
    if (reqDER != NULL) {
        SECITEM_FreeItem(reqDER, PR_TRUE);
    }
    if (signature != NULL) {
        SECITEM_FreeItem(signature, PR_TRUE);
    }
    if (algID != NULL) {
        SECOID_DestroyAlgorithmID(algID, PR_TRUE);
    }
    if (signKey != NULL) {
        CRMF_DestroyPOPOSigningKey(signKey);
    }
    return rv;
}

ErrorCode
doChallengeResponse(CGIVarTable *varTable, CRMFCertReqMsg *currReq,
                    CRMFCertRequest *certReq, CERTCertificate *newCert,
                    ChallengeCreationInfo *challs, int *numChall)
{
    CRMFPOPOPrivKey *privKey = NULL;
    CRMFPOPOPrivKeyChoice privKeyChoice;
    SECStatus srv;
    ErrorCode rv = NO_ERROR;

    srv = CRMF_CertReqMsgGetPOPKeyEncipherment(currReq, &privKey);
    if (srv != SECSuccess || privKey == NULL) {
        rv = ERROR_GETTING_KEY_ENCIPHERMENT;
        goto loser;
    }
    privKeyChoice = CRMF_POPOPrivKeyGetChoice(privKey);
    CRMF_DestroyPOPOPrivKey(privKey);
    switch (privKeyChoice) {
        case crmfSubsequentMessage:
            challs = &challs[*numChall];
            challs->random = rand();
            challs->pubKey = CERT_ExtractPublicKey(newCert);
            if (challs->pubKey == NULL) {
                rv =
                    ERROR_RETRIEVING_PUB_KEY_FOR_CHALL;
                goto loser;
            }
            (*numChall)++;
            rv = DO_CHALLENGE_RESPONSE;
            break;
        case crmfThisMessage:
            /* There'd better be a PKIArchiveControl in this message */
            if (!CRMF_CertRequestIsControlPresent(certReq,
                                                  crmfPKIArchiveOptionsControl)) {
                rv =
                    ERROR_NO_POP_FOR_PRIVKEY;
                goto loser;
            }
            break;
        default:
            rv = ERROR_UNSUPPORTED_POPOPRIVKEY_TYPE;
            goto loser;
    }
loser:
    return rv;
}

ErrorCode
doProofOfPossession(CGIVarTable *varTable, CRMFCertReqMsg *currReq,
                    CRMFCertRequest *certReq, CERTCertificate *newCert,
                    ChallengeCreationInfo *challs, int *numChall)
{
    CRMFPOPChoice popChoice;
    ErrorCode rv = NO_ERROR;

    popChoice = CRMF_CertReqMsgGetPOPType(currReq);
    if (popChoice == crmfNoPOPChoice) {
        rv = NO_POP_FOR_REQUEST;
        goto loser;
    }
    switch (popChoice) {
        case crmfSignature:
            rv = verifySignature(varTable, currReq, certReq, newCert);
            break;
        case crmfKeyEncipherment:
            rv = doChallengeResponse(varTable, currReq, certReq, newCert,
                                     challs, numChall);
            break;
        case crmfRAVerified:
        case crmfKeyAgreement:
        default:
            rv = UNSUPPORTED_POP;
            goto loser;
    }
loser:
    return rv;
}

void
convertB64ToJS(char *base64)
{
    int i;

    for (i = 0; base64[i] != '\0'; i++) {
        if (base64[i] == '\n') {
            printf("\\n");
        } else {
            printf("%c", base64[i]);
        }
    }
}

void
formatChallenge(char *chall64, char *certRepContentDER,
                ChallengeCreationInfo *challInfo, int numChalls)
{
    printf("function respondToChallenge() {\n"
           " var chalForm = document.chalForm;\n\n"
           " chalForm.CertRepContent.value = '");
    convertB64ToJS(certRepContentDER);
    printf("';\n"
           " chalForm.ChallResponse.value = crypto.popChallengeResponse('");
    convertB64ToJS(chall64);
    printf("');\n"
           " chalForm.submit();\n"
           "}\n");
}

void
spitOutChallenge(char *chall64, char *certRepContentDER,
                 ChallengeCreationInfo *challInfo, int numChalls,
                 char *nickname)
{
    int i;

    spitOutHeaders();
    printf("\n"
           "\n"
           "Challenge Page\n"
           "\n"
           "\n"
           "\n"
           "

Cartman is now responding to the Challenge "
           "presented by the CGI

\n"

           "
\n"
           "\n"
           "\n");
    for (i = 0; i < numChalls; i++) {
        printf("\n",
               i + 1, challInfo[i].random);
    }
    printf("\n", nickname);
    printf("\n\n"
);
}

ErrorCode
issueChallenge(CertResponseInfo *issuedCerts, int numCerts,
               ChallengeCreationInfo *challInfo, int numChalls,
               CERTCertificate *issuer, CGIVarTable *varTable)
{
    ErrorCode rv = NO_ERROR;
    CMMFPOPODecKeyChallContent *chalContent = NULL;
    int i;
    SECStatus srv;
    PLArenaPool *poolp;
    CERTGeneralName *genName;
    SECItem *challDER = NULL;
    char *chall64, *certRepContentDER;

    rv = createCMMFResponse(issuedCerts, numCerts, issuer,
                            &certRepContentDER);
    if (rv != NO_ERROR) {
        goto loser;
    }
    chalContent = CMMF_CreatePOPODecKeyChallContent();
    if (chalContent == NULL) {
        rv = ERROR_CREATING_EMPTY_CHAL_CONTENT;
        goto loser;
    }
    poolp = PORT_NewArena(1024);
    if (poolp == NULL) {
        rv = OUT_OF_MEMORY;
        goto loser;
    }
    genName = CERT_GetCertificateNames(issuer, poolp);
    if (genName == NULL) {
        rv = ERROR_EXTRACTING_GEN_NAME_FROM_ISSUER;
        goto loser;
    }
    for (i = 0; i < numChalls; i++) {
        srv = CMMF_POPODecKeyChallContentSetNextChallenge(chalContent,
                                                          challInfo[i].random,
                                                          genName,
                                                          challInfo[i].pubKey,
                                                          varTable);
        SECKEY_DestroyPublicKey(challInfo[i].pubKey);
        if (srv != SECSuccess) {
            rv = ERROR_SETTING_CHALLENGE;
            goto loser;
        }
    }
    challDER = SEC_ASN1EncodeItem(NULL, NULL, chalContent,
                                  CMMFPOPODecKeyChallContentTemplate);
    if (challDER == NULL) {
        rv = ERROR_ENCODING_CHALL;
        goto loser;
    }
    chall64 = BTOA_DataToAscii(challDER->data, challDER->len);
    SECITEM_FreeItem(challDER, PR_TRUE);
    if (chall64 == NULL) {
        rv = ERROR_CONVERTING_CHALL_TO_BASE64;
        goto loser;
    }
    spitOutChallenge(chall64, certRepContentDER, challInfo, numChalls,
                     getNickname(issuedCerts[0].cert));
loser:
    return rv;
}

ErrorCode
processRequest(CGIVarTable *varTable)
{
    CERTCertDBHandle *certdb;
    SECKEYKeyDBHandle *keydb;
    CRMFCertReqMessages *certReqs = NULL;
    const char *crmfReq;
    const char *caNickname;
    CERTCertificate *caCert = NULL;
    CertResponseInfo *issuedCerts = NULL;
    CERTSubjectPublicKeyInfo spki = { 0 };
    ErrorCode rv = NO_ERROR;
    PRBool doChallengeResponse = PR_FALSE;
    SECItem der = { 0 };
    SECStatus srv;
    CERTCertificateRequest oldCertReq = { 0 };
    CRMFCertReqMsg **reqMsgs = NULL, *currReq = NULL;
    CRMFCertRequest **reqs = NULL, *certReq = NULL;
    CERTName subject = { 0 };
    int numReqs, i;
    ChallengeCreationInfo *challInfo = NULL;
    int numChalls = 0;

    certdb = CERT_GetDefaultCertDB();
    keydb = SECKEY_GetDefaultKeyDB();
    crmfReq = CGITableFindValue(varTable, "CRMFRequest");
    if (crmfReq == NULL) {
        rv = CGI_VAR_MISSING;
        missingVar = "CRMFRequest";
        goto loser;
    }
    caNickname = CGITableFindValue(varTable, "CANickname");
    if (caNickname == NULL) {
        rv = CGI_VAR_MISSING;
        missingVar = "CANickname";
        goto loser;
    }
    caCert = CERT_FindCertByNickname(certdb, caNickname);
    if (caCert == NULL) {
        rv = COULD_NOT_FIND_CA;
        goto loser;
    }
    srv = ATOB_ConvertAsciiToItem(&der, crmfReq);
    if (srv != SECSuccess) {
        rv = BAD_ASCII_FOR_REQ;
        goto loser;
    }
    certReqs = CRMF_CreateCertReqMessagesFromDER(der.data, der.len);
    SECITEM_FreeItem(&der, PR_FALSE);
    if (certReqs == NULL) {
        rv = COULD_NOT_DECODE_REQS;
        goto loser;
    }
    numReqs = CRMF_CertReqMessagesGetNumMessages(certReqs);
    issuedCerts = PORT_ZNewArray(CertResponseInfo, numReqs);
    challInfo = PORT_ZNewArray(ChallengeCreationInfo, numReqs);
    if (issuedCerts == NULL || challInfo == NULL) {
        rv = OUT_OF_MEMORY;
        goto loser;
    }
    reqMsgs = PORT_ZNewArray(CRMFCertReqMsg *, numReqs);
    reqs = PORT_ZNewArray(CRMFCertRequest *, numReqs);
    if (reqMsgs == NULL || reqs == NULL) {
        rv = OUT_OF_MEMORY;
        goto loser;
    }
    for (i = 0; i < numReqs; i++) {
        currReq = reqMsgs[i] =
            CRMF_CertReqMessagesGetCertReqMsgAtIndex(certReqs, i);
        if (currReq == NULL) {
            rv = ERROR_RETRIEVING_REQUEST_MSG;
            goto loser;
        }
        certReq = reqs[i] = CRMF_CertReqMsgGetCertRequest(currReq);
        if (certReq == NULL) {
            rv = ERROR_RETRIEVING_CERT_REQUEST;
            goto loser;
        }
        srv = CRMF_CertRequestGetCertTemplateSubject(certReq, &subject);
        if (srv != SECSuccess) {
            rv = ERROR_RETRIEVING_SUBJECT_FROM_REQ;
            goto loser;
        }
        srv = CRMF_CertRequestGetCertTemplatePublicKey(certReq, &spki);
        if (srv != SECSuccess) {
            rv = ERROR_RETRIEVING_PUBLIC_KEY_FROM_REQ;
            goto loser;
        }
        rv = initOldCertReq(&oldCertReq, &subject, &spki);
        if (rv != NO_ERROR) {
            goto loser;
        }
        rv = createNewCert(&issuedCerts[i].cert, &oldCertReq, currReq, certReq,
                           caCert, varTable);
        if (rv != NO_ERROR) {
            goto loser;
        }
        rv = doProofOfPossession(varTable, currReq, certReq, issuedCerts[i].cert,
                                 challInfo, &numChalls);
        if (rv != NO_ERROR) {
            if (rv == DO_CHALLENGE_RESPONSE) {
                doChallengeResponse = PR_TRUE;
            } else {
                goto loser;
            }
        }
        CRMF_CertReqMsgGetID(currReq, &issuedCerts[i].certReqID);
        CRMF_DestroyCertReqMsg(currReq);
        CRMF_DestroyCertRequest(certReq);
    }
    if (doChallengeResponse) {
        rv = issueChallenge(issuedCerts, numReqs, challInfo, numChalls, caCert,
                            varTable);
    } else {
        rv = issueCerts(issuedCerts, numReqs, caCert);
    }
loser:
    if (certReqs != NULL) {
        CRMF_DestroyCertReqMessages(certReqs);
    }
    return rv;
}

ErrorCode
processChallengeResponse(CGIVarTable *varTable, const char *certRepContent)
{
    SECItem binDER = { 0 };
    SECStatus srv;
    ErrorCode rv = NO_ERROR;
    const char *clientResponse;
    const char *formChalValue;
    const char *nickname;
    CMMFPOPODecKeyRespContent *respContent = NULL;
    int numResponses, i;
    long curResponse, expectedResponse;
    char cgiChalVar[10];
#ifdef WRITE_OUT_RESPONSE
    SECItem certRepBinDER = { 0 };

    ATOB_ConvertAsciiToItem(&certRepBinDER, certRepContent);
    writeOutItem("challCertRepContent.der", &certRepBinDER);
    PORT_Free(certRepBinDER.data);
#endif
    clientResponse = CGITableFindValue(varTable, "ChallResponse");
    if (clientResponse == NULL) {
        rv = REQ_CGI_VAR_NOT_PRESENT;
        missingVar = "ChallResponse";
        goto loser;
    }
    srv = ATOB_ConvertAsciiToItem(&binDER, clientResponse);
    if (srv != SECSuccess) {
        rv = ERROR_CONVERTING_RESP_FROM_CHALL_TO_BIN;
        goto loser;
    }
    respContent = CMMF_CreatePOPODecKeyRespContentFromDER(binDER.data,
                                                          binDER.len);
    SECITEM_FreeItem(&binDER, PR_FALSE);
    binDER.data = NULL;
    if (respContent == NULL) {
        rv = ERROR_CREATING_KEY_RESP_FROM_DER;
        goto loser;
    }
    numResponses = CMMF_POPODecKeyRespContentGetNumResponses(respContent);
    for (i = 0; i < numResponses; i++) {
        srv = CMMF_POPODecKeyRespContentGetResponse(respContent, i, &curResponse);
        if (srv != SECSuccess) {
            rv = ERROR_RETRIEVING_CLIENT_RESPONSE_TO_CHALLENGE;
            goto loser;
        }
        snprintf(cgiChalVar, sizeof(cgiChalVar), "chal%d", i + 1);
        formChalValue = CGITableFindValue(varTable, cgiChalVar);
        if (formChalValue == NULL) {
            rv = REQ_CGI_VAR_NOT_PRESENT;
            missingVar = strdup(cgiChalVar);
            goto loser;
        }
        sscanf(formChalValue, "%ld", &expectedResponse);
        if (expectedResponse != curResponse) {
            rv = ERROR_RETURNED_CHALL_NOT_VALUE_EXPECTED;
            goto loser;
        }
    }
    nickname = CGITableFindValue(varTable, "nickname");
    if (nickname == NULL) {
        rv = REQ_CGI_VAR_NOT_PRESENT;
        missingVar = "nickname";
        goto loser;
    }
    spitOutCMMFResponse(nickname, certRepContent);
loser:
    if (respContent != NULL) {
        CMMF_DestroyPOPODecKeyRespContent(respContent);
    }
    return rv;
}

int
main()
{
    char *form_output = NULL;
    int form_output_len, form_output_used;
    CGIVarTable varTable = { 0 };
    ErrorCode errNum = 0;
    char *certRepContent;

#ifdef ATTACH_CGI
    /* Put an ifinite loop in here so I can attach to
     * the process after the process is spun off
     */

    {
        int stupid = 1;
        while (stupid)
            ;
    }
#endif

    form_output_used = 0;
    srand(time(NULL));
    while (feof(stdin) == 0) {
        if (form_output == NULL) {
            form_output = PORT_NewArray(char, DEFAULT_ALLOC_SIZE + 1);
            form_output_len = DEFAULT_ALLOC_SIZE;
        } else if ((form_output_used + DEFAULT_ALLOC_SIZE) >= form_output_len) {
            form_output_len += DEFAULT_ALLOC_SIZE;
            form_output = PORT_Realloc(form_output, form_output_len + 1);
        }
        form_output_used += fread(&form_output[form_output_used], sizeof(char),
                                  DEFAULT_ALLOC_SIZE, stdin);
    }
    ParseInputVariables(&varTable, form_output);
    certRepContent = CGITableFindValue(&varTable, "CertRepContent");
    if (certRepContent == NULL) {
        errNum = initNSS(&varTable);
        if (errNum != 0) {
            goto loser;
        }
        errNum = processRequest(&varTable);
    } else {
        errNum = processChallengeResponse(&varTable, certRepContent);
    }
    if (errNum != NO_ERROR) {
        goto loser;
    }
    goto done;
loser:
    dumpErrorMessage(errNum);
done:
    free(form_output);
    return 0;
}

Messung V0.5
C=99 H=65 G=83

¤ Dauer der Verarbeitung: 0.3 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.