Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  pk12util.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/. */


#ifdef _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#endif

#include "nspr.h"
#include "secutil.h"
#include "pk11func.h"
#include "pkcs12.h"
#include "p12plcy.h"
#include "pk12util.h"
#include "nss.h"
#include "secport.h"
#include "secpkcs5.h"
#include "sechash.h"
#include "certdb.h"

#define PKCS12_IN_BUFFER_SIZE 200

static char *progName;
PRBool pk12_debugging = PR_FALSE;
PRBool dumpRawFile;
static PRBool pk12uForceUnicode;

PRIntn pk12uErrno = 0;

static void
Usage()
{
#define FPS PR_fprintf(PR_STDERR,
    FPS "Usage: %s -i importfile [-I] [-d certdir] [-P dbprefix] [-h tokenname]\n",
     progName);
    FPS "\t\t [-k slotpwfile | -K slotpw] [-w p12filepwfile | -W p12filepw]\n");
    FPS "\t\t [-v]\n");

    FPS "Usage: %s -l listfile [-I] [-d certdir] [-P dbprefix] [-h tokenname]\n",
     progName);
    FPS "\t\t [-k slotpwfile | -K slotpw] [-w p12filepwfile | -W p12filepw]\n");
    FPS "\t\t [-v]\n");

    FPS "Usage: %s -o exportfile -n certname [-d certdir] [-P dbprefix]\n",
  progName);
    FPS "\t\t [-c key_cipher] [-C cert_cipher] [-M mac_alg]\n"
        "\t\t [-m | --key_len keyLen] [--cert_key_len certKeyLen] [-v]\n");
    FPS "\t\t [-k slotpwfile | -K slotpw]\n"
        "\t\t [-w p12filepwfile | -W p12filepw]\n");

    exit(PK12UERR_USAGE);
}

static PRBool
p12u_OpenFile(p12uContext *p12cxt, PRBool fileRead)
{
    if (!p12cxt || !p12cxt->filename) {
        return PR_FALSE;
    }

    if (fileRead) {
        p12cxt->file = PR_Open(p12cxt->filename,
                               PR_RDONLY, 0400);
    } else {
        p12cxt->file = PR_Open(p12cxt->filename,
                               PR_CREATE_FILE | PR_RDWR | PR_TRUNCATE,
                               0600);
    }

    if (!p12cxt->file) {
        p12cxt->error = PR_TRUE;
        return PR_FALSE;
    }

    return PR_TRUE;
}

static void
p12u_DestroyContext(p12uContext **ppCtx, PRBool removeFile)
{
    if (!ppCtx || !(*ppCtx)) {
        return;
    }

    if ((*ppCtx)->file != NULL) {
        PR_Close((*ppCtx)->file);
    }

    if ((*ppCtx)->filename != NULL) {
        if (removeFile) {
            PR_Delete((*ppCtx)->filename);
        }
        PL_strfree((*ppCtx)->filename);
        (*ppCtx)->filename = NULL;
    }

    PR_Free(*ppCtx);
    *ppCtx = NULL;
}

static p12uContext *
p12u_InitContext(PRBool fileImport, char *filename)
{
    p12uContext *p12cxt;

    p12cxt = PORT_ZNew(p12uContext);
    if (!p12cxt) {
        return NULL;
    }

    p12cxt->error = PR_FALSE;
    p12cxt->errorValue = 0;
    p12cxt->filename = PL_strdup(filename);

    if (!p12u_OpenFile(p12cxt, fileImport)) {
        p12u_DestroyContext(&p12cxt, PR_FALSE);
        return NULL;
    }

    return p12cxt;
}

SECItem *
P12U_NicknameCollisionCallback(SECItem *old_nick, PRBool *cancel, void *wincx)
{
    char *nick = NULL;
    SECItem *ret_nick = NULL;
    CERTCertificate *cert = (CERTCertificate *)wincx;

    if (!cancel || !cert) {
        pk12uErrno = PK12UERR_USER_CANCELLED;
        return NULL;
    }

    if (!old_nick)
        fprintf(stdout, "pk12util: no nickname for cert in PKCS12 file.\n");

#if 0
    /* XXX not handled yet  */
    *cancel = PR_TRUE;
    return NULL;

#else

    nick = CERT_MakeCANickname(cert);
    if (!nick) {
        return NULL;
    }

    if (old_nick && old_nick->data && old_nick->len &&
        PORT_Strlen(nick) == old_nick->len &&
        !PORT_Strncmp((char *)old_nick->data, nick, old_nick->len)) {
        PORT_Free(nick);
        PORT_SetError(SEC_ERROR_IO);
        return NULL;
    }

    fprintf(stdout, "pk12util: using nickname: %s\n", nick);
    ret_nick = PORT_ZNew(SECItem);
    if (ret_nick == NULL) {
        PORT_Free(nick);
        return NULL;
    }

    ret_nick->data = (unsigned char *)nick;
    ret_nick->len = PORT_Strlen(nick);

    return ret_nick;
#endif
}

static SECStatus
p12u_SwapUnicodeBytes(SECItem *uniItem)
{
    unsigned int i;
    unsigned char a;
    if ((uniItem == NULL) || (uniItem->len % 2)) {
        return SECFailure;
    }
    for (i = 0; i < uniItem->len; i += 2) {
        a = uniItem->data[i];
        uniItem->data[i] = uniItem->data[i + 1];
        uniItem->data[i + 1] = a;
    }
    return SECSuccess;
}

static PRBool
p12u_ucs2_ascii_conversion_function(PRBool toUnicode,
                                    unsigned char *inBuf,
                                    unsigned int inBufLen,
                                    unsigned char *outBuf,
                                    unsigned int maxOutBufLen,
                                    unsigned int *outBufLen,
                                    PRBool swapBytes)
{
    SECItem it = { 0 };
    SECItem *dup = NULL;
    PRBool ret;

#ifdef DEBUG_CONVERSION
    if (pk12_debugging) {
        int i;
        printf("Converted from:\n");
        for (i = 0; i < inBufLen; i++) {
            printf("%2x ", inBuf[i]);
            /*if (i%60 == 0) printf("\n");*/
        }
        printf("\n");
    }
#endif
    it.data = inBuf;
    it.len = inBufLen;
    dup = SECITEM_DupItem(&it);
    if (!dup) {
        return PR_FALSE;
    }
    /* If converting Unicode to ASCII, swap bytes before conversion
     * as neccessary.
     */

    if (!toUnicode && swapBytes) {
        if (p12u_SwapUnicodeBytes(dup) != SECSuccess) {
            SECITEM_ZfreeItem(dup, PR_TRUE);
            return PR_FALSE;
        }
    }
    /* Perform the conversion. */
    ret = PORT_UCS2_UTF8Conversion(toUnicode, dup->data, dup->len,
                                   outBuf, maxOutBufLen, outBufLen);
    SECITEM_ZfreeItem(dup, PR_TRUE);

#ifdef DEBUG_CONVERSION
    if (pk12_debugging) {
        int i;
        printf("Converted to:\n");
        for (i = 0; i < *outBufLen; i++) {
            printf("%2x ", outBuf[i]);
            /*if (i%60 == 0) printf("\n");*/
        }
        printf("\n");
    }
#endif
    return ret;
}

SECStatus
P12U_UnicodeConversion(PLArenaPool *arena, SECItem *dest, SECItem *src,
                       PRBool toUnicode, PRBool swapBytes)
{
    unsigned int allocLen;
    if (!dest || !src) {
        return SECFailure;
    }
    allocLen = ((toUnicode) ? (src->len << 2) : src->len);
    if (arena) {
        dest->data = PORT_ArenaZAlloc(arena, allocLen);
    } else {
        dest->data = PORT_ZAlloc(allocLen);
    }
    if (PORT_UCS2_ASCIIConversion(toUnicode, src->data, src->len,
                                  dest->data, allocLen, &dest->len,
                                  swapBytes) == PR_FALSE) {
        if (!arena) {
            PORT_Free(dest->data);
        }
        dest->data = NULL;
        return SECFailure;
    }
    return SECSuccess;
}

/*
 *
 */

SECItem *
P12U_GetP12FilePassword(PRBool confirmPw, secuPWData *p12FilePw)
{
    char *p0 = NULL;
    SECItem *pwItem = NULL;

    if (p12FilePw == NULL || p12FilePw->source == PW_NONE) {
        char *p1 = NULL;
        int rc;
        for (;;) {
            p0 = SECU_GetPasswordString(NULL,
                                        "Enter password for PKCS12 file: ");
            if (!confirmPw || p0 == NULL)
                break;
            p1 = SECU_GetPasswordString(NULL, "Re-enter password: ");
            if (p1 == NULL) {
                PORT_ZFree(p0, PL_strlen(p0));
                p0 = NULL;
                break;
            }
            rc = PL_strcmp(p0, p1);
            PORT_ZFree(p1, PL_strlen(p1));
            if (rc == 0)
                break;
            PORT_ZFree(p0, PL_strlen(p0));
        }
    } else if (p12FilePw->source == PW_FROMFILE) {
        p0 = SECU_FilePasswd(NULL, PR_FALSE, p12FilePw->data);
    } else { /* Plaintext */
        p0 = PORT_Strdup(p12FilePw->data);
    }

    if (p0 == NULL) {
        return NULL;
    }
    pwItem = SECITEM_AllocItem(NULL, NULL, PL_strlen(p0) + 1);
    memcpy(pwItem->data, p0, pwItem->len);

    PORT_ZFree(p0, PL_strlen(p0));

    return pwItem;
}

SECStatus
P12U_InitSlot(PK11SlotInfo *slot, secuPWData *slotPw)
{
    SECStatus rv;

    /* New databases, initialize keydb password. */
    if (PK11_NeedUserInit(slot)) {
        rv = SECU_ChangePW(slot,
                           (slotPw->source == PW_PLAINTEXT) ? slotPw->data : 0,
                           (slotPw->source == PW_FROMFILE) ? slotPw->data : 0);
        if (rv != SECSuccess) {
            SECU_PrintError(progName, "Failed to initialize slot \"%s\"",
                            PK11_GetSlotName(slot));
            return SECFailure;
        }
    }

    if (PK11_Authenticate(slot, PR_TRUE, slotPw) != SECSuccess) {
        SECU_PrintError(progName,
                        "Failed to authenticate to PKCS11 slot");
        PORT_SetError(SEC_ERROR_USER_CANCELLED);
        pk12uErrno = PK12UERR_USER_CANCELLED;
        return SECFailure;
    }

    return SECSuccess;
}

/* This routine takes care of getting the PKCS12 file password, then reading and
 * verifying the file. It returns the decoder context and a filled in password.
 * (The password is needed by P12U_ImportPKCS12Object() to import the private
 * key.)
 */

SEC_PKCS12DecoderContext *
p12U_ReadPKCS12File(SECItem *uniPwp, char *in_file, PK11SlotInfo *slot,
                    secuPWData *slotPw, secuPWData *p12FilePw,
                    PRBool ignoreIntegrity)
{
    SEC_PKCS12DecoderContext *p12dcx = NULL;
    p12uContext *p12cxt = NULL;
    SECItem *pwitem = NULL;
    SECItem p12file = { 0 };
    SECStatus rv = SECFailure;
    PRBool swapUnicode = PR_FALSE;
    PRBool forceUnicode = pk12uForceUnicode;
    PRBool trypw;
    int error;

#ifdef IS_LITTLE_ENDIAN
    swapUnicode = PR_TRUE;
#endif

    p12cxt = p12u_InitContext(PR_TRUE, in_file);
    if (!p12cxt) {
        SECU_PrintError(progName, "File Open failed: %s", in_file);
        pk12uErrno = PK12UERR_INIT_FILE;
        return NULL;
    }

    /* get the password */
    pwitem = P12U_GetP12FilePassword(PR_FALSE, p12FilePw);
    if (!pwitem) {
        pk12uErrno = PK12UERR_USER_CANCELLED;
        goto done;
    }

    if (P12U_UnicodeConversion(NULL, uniPwp, pwitem, PR_TRUE,
                               swapUnicode) != SECSuccess) {
        SECU_PrintError(progName, "Unicode conversion failed");
        pk12uErrno = PK12UERR_UNICODECONV;
        goto done;
    }
    rv = SECU_FileToItem(&p12file, p12cxt->file);
    if (rv != SECSuccess) {
        SECU_PrintError(progName, "Failed to read from import file");
        goto done;
    }

    do {
        trypw = PR_FALSE; /* normally we do this once */
        rv = SECFailure;
        /* init the decoder context */
        p12dcx = SEC_PKCS12DecoderStart(uniPwp, slot, slotPw,
                                        NULL, NULL, NULL, NULL, NULL);
        if (!p12dcx) {
            SECU_PrintError(progName, "PKCS12 decoder start failed");
            pk12uErrno = PK12UERR_PK12DECODESTART;
            break;
        }

        /* decode the item */
        rv = SEC_PKCS12DecoderUpdate(p12dcx, p12file.data, p12file.len);

        if (rv != SECSuccess) {
            error = PR_GetError();
            if (error == SEC_ERROR_DECRYPTION_DISALLOWED) {
                PR_SetError(error, 0);
                break;
            }
            SECU_PrintError(progName, "PKCS12 decoding failed");
            pk12uErrno = PK12UERR_DECODE;
        }

        /* does the blob authenticate properly? */
        rv = SEC_PKCS12DecoderVerify(p12dcx);
        if (rv != SECSuccess) {
            if (uniPwp->len == 2) {
                /* this is a null PW, try once more with a zero-length PW
                   instead of a null string */

                SEC_PKCS12DecoderFinish(p12dcx);
                uniPwp->len = 0;
                trypw = PR_TRUE;
            } else if (forceUnicode == pk12uForceUnicode) {
                /* try again with a different password encoding */
                forceUnicode = !pk12uForceUnicode;
                rv = NSS_OptionSet(__NSS_PKCS12_DECODE_FORCE_UNICODE,
                                   forceUnicode);
                if (rv != SECSuccess) {
                    SECU_PrintError(progName, "PKCS12 decoding failed to set option");
                    pk12uErrno = PK12UERR_DECODEVERIFY;
                    break;
                }
                SEC_PKCS12DecoderFinish(p12dcx);
                trypw = PR_TRUE;
            } else {
                SECU_PrintError(progName, "PKCS12 decode not verified");
                pk12uErrno = PK12UERR_DECODEVERIFY;
                break;
            }
        }
    } while (trypw == PR_TRUE);

    /* revert the option setting */
    if (forceUnicode != pk12uForceUnicode) {
        if (SECSuccess != NSS_OptionSet(__NSS_PKCS12_DECODE_FORCE_UNICODE, pk12uForceUnicode)) {
            SECU_PrintError(progName, "PKCS12 decoding failed to set option");
            pk12uErrno = PK12UERR_DECODEVERIFY;
            rv = SECFailure;
        }
    }
    /* rv has been set at this point */

done:
    /* if we are ignoring Integrity and we failed because we couldn't
     * verify the integrity code, go ahead and succeed */

    if (rv != SECSuccess && !(ignoreIntegrity &&
                              (pk12uErrno == PK12UERR_DECODEVERIFY))) {
        if (p12dcx != NULL) {
            SEC_PKCS12DecoderFinish(p12dcx);
            p12dcx = NULL;
        }
        if (uniPwp->data) {
            SECITEM_ZfreeItem(uniPwp, PR_FALSE);
            uniPwp->data = NULL;
        }
    }
    PR_Close(p12cxt->file);
    p12cxt->file = NULL;
    /* PK11_FreeSlot(slot); */
    p12u_DestroyContext(&p12cxt, PR_FALSE);

    if (pwitem) {
        SECITEM_ZfreeItem(pwitem, PR_TRUE);
    }
    SECITEM_ZfreeItem(&p12file, PR_FALSE);
    return p12dcx;
}

/*
 * given a filename for pkcs12 file, imports certs and keys
 *
 * Change: altitude
 *  I've changed this function so that it takes the keydb and pkcs12 file
 *  passwords from files.  The "pwdKeyDB" and "pwdP12File"
 *  variables have been added for this purpose.
 */

PRIntn
P12U_ImportPKCS12Object(char *in_file, PK11SlotInfo *slot,
                        secuPWData *slotPw, secuPWData *p12FilePw,
                        PRBool ignoreIntegrity)
{
    SEC_PKCS12DecoderContext *p12dcx = NULL;
    SECItem uniPwitem = { 0 };
    PRBool forceUnicode = pk12uForceUnicode;
    PRBool trypw;
    SECStatus rv = SECFailure;

    rv = P12U_InitSlot(slot, slotPw);
    if (rv != SECSuccess) {
        SECU_PrintError(progName, "Failed to authenticate to \"%s\"",
                        PK11_GetSlotName(slot));
        pk12uErrno = PK12UERR_PK11GETSLOT;
        return rv;
    }

    do {
        trypw = PR_FALSE; /* normally we do this once */
        rv = SECFailure;
        p12dcx = p12U_ReadPKCS12File(&uniPwitem, in_file, slot, slotPw,
                                     p12FilePw, ignoreIntegrity);

        if (p12dcx == NULL) {
            goto loser;
        }

        /* make sure the bags are okey dokey -- nicknames correct, etc. */
        rv = SEC_PKCS12DecoderValidateBags(p12dcx, P12U_NicknameCollisionCallback);
        if (rv != SECSuccess) {
            if (PORT_GetError() == SEC_ERROR_PKCS12_DUPLICATE_DATA) {
                pk12uErrno = PK12UERR_CERTALREADYEXISTS;
            } else {
                pk12uErrno = PK12UERR_DECODEVALIBAGS;
            }
            SECU_PrintError(progName, "PKCS12 decode validate bags failed");
            goto loser;
        }

        /* stuff 'em in */
        if (forceUnicode != pk12uForceUnicode) {
            rv = NSS_OptionSet(__NSS_PKCS12_DECODE_FORCE_UNICODE,
                               forceUnicode);
            if (rv != SECSuccess) {
                SECU_PrintError(progName, "PKCS12 decode set option failed");
                pk12uErrno = PK12UERR_DECODEIMPTBAGS;
                goto loser;
            }
        }
        rv = SEC_PKCS12DecoderImportBags(p12dcx);
        if (rv != SECSuccess) {
            if (PR_GetError() == SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY &&
                forceUnicode == pk12uForceUnicode) {
                /* try again with a different password encoding */
                forceUnicode = !pk12uForceUnicode;
                SEC_PKCS12DecoderFinish(p12dcx);
                SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);
                trypw = PR_TRUE;
            } else {
                SECU_PrintError(progName, "PKCS12 decode import bags failed");
                pk12uErrno = PK12UERR_DECODEIMPTBAGS;
                goto loser;
            }
        }
    } while (trypw);

    /* revert the option setting */
    if (forceUnicode != pk12uForceUnicode) {
        rv = NSS_OptionSet(__NSS_PKCS12_DECODE_FORCE_UNICODE, pk12uForceUnicode);
        if (rv != SECSuccess) {
            SECU_PrintError(progName, "PKCS12 decode set option failed");
            pk12uErrno = PK12UERR_DECODEIMPTBAGS;
            goto loser;
        }
    }

    fprintf(stdout, "%s: PKCS12 IMPORT SUCCESSFUL\n", progName);
    rv = SECSuccess;

loser:
    if (p12dcx) {
        SEC_PKCS12DecoderFinish(p12dcx);
    }

    if (uniPwitem.data) {
        SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);
    }

    return rv;
}

static void
p12u_DoPKCS12ExportErrors()
{
    PRErrorCode error_value;

    error_value = PORT_GetError();
    if ((error_value == SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY) ||
        (error_value == SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME) ||
        (error_value == SEC_ERROR_PKCS12_UNABLE_TO_WRITE)) {
        fputs(SECU_Strerror(error_value), stderr);
    } else if (error_value == SEC_ERROR_USER_CANCELLED) {
        ;
    } else {
        fputs(SECU_Strerror(SEC_ERROR_EXPORTING_CERTIFICATES), stderr);
    }
}

static void
p12u_WriteToExportFile(void *arg, const char *buf, unsigned long len)
{
    p12uContext *p12cxt = arg;
    int writeLen;

    if (!p12cxt || (p12cxt->error == PR_TRUE)) {
        return;
    }

    if (p12cxt->file == NULL) {
        p12cxt->errorValue = SEC_ERROR_PKCS12_UNABLE_TO_WRITE;
        p12cxt->error = PR_TRUE;
        return;
    }

    writeLen = PR_Write(p12cxt->file, (unsigned char *)buf, (PRInt32)len);

    if (writeLen != (int)len) {
        PR_Close(p12cxt->file);
        PL_strfree(p12cxt->filename);
        p12cxt->filename = NULL;
        p12cxt->file = NULL;
        p12cxt->errorValue = SEC_ERROR_PKCS12_UNABLE_TO_WRITE;
        p12cxt->error = PR_TRUE;
    }
}

void
P12U_ExportPKCS12Object(char *nn, char *outfile, PK11SlotInfo *inSlot,
                        SECOidTag cipher, SECOidTag certCipher, SECOidTag hash,
                        secuPWData *slotPw, secuPWData *p12FilePw)
{
    SEC_PKCS12ExportContext *p12ecx = NULL;
    SEC_PKCS12SafeInfo *keySafe = NULL, *certSafe = NULL;
    SECItem *pwitem = NULL;
    p12uContext *p12cxt = NULL;
    CERTCertList *certlist = NULL;
    CERTCertListNode *node = NULL;
    PK11SlotInfo *slot = NULL;

    if (P12U_InitSlot(inSlot, slotPw) != SECSuccess) {
        SECU_PrintError(progName, "Failed to authenticate to \"%s\"",
                        PK11_GetSlotName(inSlot));
        pk12uErrno = PK12UERR_PK11GETSLOT;
        goto loser;
    }
    certlist = PK11_FindCertsFromNickname(nn, slotPw);
    if (!certlist) {
        PORT_SetError(SEC_ERROR_UNKNOWN_CERT);
        SECU_PrintError(progName, "find user certs from nickname failed");
        pk12uErrno = PK12UERR_FINDCERTBYNN;
        return;
    }

    if ((SECSuccess != CERT_FilterCertListForUserCerts(certlist)) ||
        CERT_LIST_EMPTY(certlist)) {
        PR_fprintf(PR_STDERR, "%s: no user certs from given nickname\n",
                   progName);
        pk12uErrno = PK12UERR_FINDCERTBYNN;
        goto loser;
    }

    /* Password to use for PKCS12 file.  */
    pwitem = P12U_GetP12FilePassword(PR_TRUE, p12FilePw);
    if (!pwitem) {
        goto loser;
    }

    /* we are passing UTF8, drop the NULL in the normal password value.
     * UCS2 conversion will add it back if necessary. This only affects
     * password > Blocksize of the Hash function and pkcs5v2 pbe (if password
     * <=Blocksize then the password is zero padded anyway, so an extra NULL
     * at the end has not effect). This is allows us to work with openssl and
     * gnutls. Older versions of NSS already fail to decrypt long passwords
     * in this case, so we aren't breaking anyone with this code */

    if ((pwitem->len > 0) && (!pwitem->data[pwitem->len - 1])) {
        pwitem->len--;
    }

    p12cxt = p12u_InitContext(PR_FALSE, outfile);
    if (!p12cxt) {
        SECU_PrintError(progName, "Initialization failed: %s", outfile);
        pk12uErrno = PK12UERR_INIT_FILE;
        goto loser;
    }

    if (certlist) {
        CERTCertificate *cert = CERT_LIST_HEAD(certlist)->cert;
        if (cert) {
            slot = cert->slot; /* use the slot from the first matching
                certificate to create the context . This is for keygen */

        }
    }
    if (!slot) {
        SECU_PrintError(progName, "cert does not have a slot");
        pk12uErrno = PK12UERR_FINDCERTBYNN;
        goto loser;
    }
    p12ecx = SEC_PKCS12CreateExportContext(NULL, NULL, slot, slotPw);
    if (!p12ecx) {
        SECU_PrintError(progName, "export context creation failed");
        pk12uErrno = PK12UERR_EXPORTCXCREATE;
        goto loser;
    }

    if (SEC_PKCS12AddPasswordIntegrity(p12ecx, pwitem, hash) !=
        SECSuccess) {
        SECU_PrintError(progName, "PKCS12 add password integrity failed");
        pk12uErrno = PK12UERR_PK12ADDPWDINTEG;
        goto loser;
    }

    for (node = CERT_LIST_HEAD(certlist);
         !CERT_LIST_END(node, certlist);
         node = CERT_LIST_NEXT(node)) {
        CERTCertificate *cert = node->cert;
        if (!cert->slot) {
            SECU_PrintError(progName, "cert does not have a slot");
            pk12uErrno = PK12UERR_FINDCERTBYNN;
            goto loser;
        }

        keySafe = SEC_PKCS12CreateUnencryptedSafe(p12ecx);
        if (certCipher == SEC_OID_UNKNOWN) {
            certSafe = keySafe;
        } else {
            certSafe =
                SEC_PKCS12CreatePasswordPrivSafe(p12ecx, pwitem, certCipher);
        }

        if (!certSafe || !keySafe) {
            SECU_PrintError(progName, "key or cert safe creation failed");
            pk12uErrno = PK12UERR_CERTKEYSAFE;
            goto loser;
        }

        if (SEC_PKCS12AddCertAndKey(p12ecx, certSafe, NULL, cert,
                                    CERT_GetDefaultCertDB(), keySafe, NULL,
                                    PR_TRUE, pwitem, cipher) != SECSuccess) {
            SECU_PrintError(progName, "add cert and key failed");
            pk12uErrno = PK12UERR_ADDCERTKEY;
            goto loser;
        }
    }

    CERT_DestroyCertList(certlist);
    certlist = NULL;

    if (SEC_PKCS12Encode(p12ecx, p12u_WriteToExportFile, p12cxt) !=
        SECSuccess) {
        SECU_PrintError(progName, "PKCS12 encode failed");
        pk12uErrno = PK12UERR_ENCODE;
        goto loser;
    }

    p12u_DestroyContext(&p12cxt, PR_FALSE);
    SECITEM_ZfreeItem(pwitem, PR_TRUE);
    fprintf(stdout, "%s: PKCS12 EXPORT SUCCESSFUL\n", progName);
    SEC_PKCS12DestroyExportContext(p12ecx);

    return;

loser:
    SEC_PKCS12DestroyExportContext(p12ecx);

    if (certlist) {
        CERT_DestroyCertList(certlist);
        certlist = NULL;
    }

    p12u_DestroyContext(&p12cxt, PR_TRUE);
    if (pwitem) {
        SECITEM_ZfreeItem(pwitem, PR_TRUE);
    }
    p12u_DoPKCS12ExportErrors();
    return;
}

PRIntn
P12U_ListPKCS12File(char *in_file, PK11SlotInfo *slot,
                    secuPWData *slotPw, secuPWData *p12FilePw,
                    PRBool ignoreIntegrity)
{
    SEC_PKCS12DecoderContext *p12dcx = NULL;
    SECItem uniPwitem = { 0 };
    SECStatus rv = SECFailure;
    const SEC_PKCS12DecoderItem *dip;

    p12dcx = p12U_ReadPKCS12File(&uniPwitem, in_file, slot, slotPw, p12FilePw,
                                 ignoreIntegrity);
    /* did the blob authenticate properly? */
    if (p12dcx == NULL) {
        SECU_PrintError(progName, "PKCS12 decode not verified");
        pk12uErrno = PK12UERR_DECODEVERIFY;
        goto loser;
    }
    rv = SEC_PKCS12DecoderIterateInit(p12dcx);
    if (rv != SECSuccess) {
        SECU_PrintError(progName, "PKCS12 decode iterate bags failed");
        pk12uErrno = PK12UERR_DECODEIMPTBAGS;
        rv = SECFailure;
    } else {
        int fileCounter = 0;
        while (SEC_PKCS12DecoderIterateNext(p12dcx, &dip) == SECSuccess) {
            switch (dip->type) {
                case SEC_OID_PKCS12_V1_CERT_BAG_ID:
                    printf("Certificate");
                    if (dumpRawFile) {
                        PRFileDesc *fd;
                        char fileName[20];
                        snprintf(fileName, sizeof(fileName), "file%04d.der", ++fileCounter);
                        fd = PR_Open(fileName,
                                     PR_CREATE_FILE | PR_RDWR | PR_TRUNCATE,
                                     0600);
                        if (!fd) {
                            SECU_PrintError(progName,
                                            "Cannot create output file");
                        } else {
                            PR_Write(fd, dip->der->data, dip->der->len);
                            PR_Close(fd);
                        }
                    } else if (SECU_PrintSignedData(stdout, dip->der,
                                                    (dip->hasKey) ? "(has private key)"
                                                                  : "",
                                                    0, SECU_PrintCertificate) !=
                               0) {
                        SECU_PrintError(progName, "PKCS12 print cert bag failed");
                    }
                    if (dip->friendlyName != NULL) {
                        printf(" Friendly Name: %s\n\n",
                               dip->friendlyName->data);
                    }
                    if (dip->shroudAlg) {
                        SECU_PrintAlgorithmID(stdout, dip->shroudAlg,
                                              "Encryption algorithm", 1);
                    }
                    break;
                case SEC_OID_PKCS12_V1_KEY_BAG_ID:
                case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
                    printf("Key");
                    if (dip->type == SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID)
                        printf("(shrouded)");
                    printf(":\n");
                    if (dip->friendlyName != NULL) {
                        printf(" Friendly Name: %s\n\n",
                               dip->friendlyName->data);
                    }
                    if (dip->shroudAlg) {
                        SECU_PrintAlgorithmID(stdout, dip->shroudAlg,
                                              "Encryption algorithm", 1);
                    }
                    break;
                default:
                    printf("unknown bag type(%d): %s\n\n", dip->type,
                           SECOID_FindOIDTagDescription(dip->type));
                    break;
            }
        }
        rv = SECSuccess;
    }

loser:

    if (p12dcx) {
        SEC_PKCS12DecoderFinish(p12dcx);
    }

    if (uniPwitem.data) {
        SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);
    }

    return rv;
}

SECOidTag
PKCS12U_FindTagFromString(char *cipherString)
{
    SECOidTag tag;
    SECOidData *oid;

    /* future enhancement: accept dotted oid spec? */

    for (tag = 1; (oid = SECOID_FindOIDByTag(tag)) != NULL; tag++) {
        /* only interested in oids that we actually understand */
        if (oid->mechanism == CKM_INVALID_MECHANISM) {
            continue;
        }
        if (PORT_Strcasecmp(oid->desc, cipherString) != 0) {
            continue;
        }
        return tag;
    }
    return SEC_OID_UNKNOWN;
}

/*
 * use the oid table description to map a user input string to a particular
 * oid.
 */

SECOidTag
PKCS12U_MapCipherFromString(char *cipherString, int keyLen)
{
    SECOidTag tag;
    SECOidTag cipher;

    /* future enhancement: provide 'friendlier' typed in names for
     * pbe mechanisms.
     */


    /* look for the oid tag by Description */
    tag = PKCS12U_FindTagFromString(cipherString);
    if (tag == SEC_OID_UNKNOWN) {
        return tag;
    }

    cipher = SEC_OID_UNKNOWN;
    /* we found a match... get the PBE version of this
     * cipher... */

    if (!SEC_PKCS5IsAlgorithmPBEAlgTag(tag)) {
        cipher = SEC_PKCS5GetPBEAlgorithm(tag, keyLen);
        /* no eqivalent PKCS5/PKCS12 cipher, use the raw
         * encryption tag we got and pass it directly in,
         * pkcs12 will use the pkcsv5 mechanism */

        if (cipher == SEC_OID_PKCS5_PBES2) {
            cipher = tag;
        } else if (cipher == SEC_OID_PKCS5_PBMAC1) {
            /* make sure we have not macing ciphers here */
            cipher = SEC_OID_UNKNOWN;
        }
    } else {
        cipher = tag;
    }
    return cipher;
}

SECOidTag
PKCS12U_MapHashFromString(char *hashString)
{
    SECOidTag hashAlg;

    /* look for the oid tag by Description */
    hashAlg = PKCS12U_FindTagFromString(hashString);
    if (hashAlg == SEC_OID_UNKNOWN) {
        return hashAlg;
    }
    /* make sure it's a hashing oid */
    if (HASH_GetHashTypeByOidTag(hashAlg) == HASH_AlgNULL) {
        /* allow HMAC here. HMAC implies PKCS 5 v2 pba */
        SECOidTag baseHashAlg = HASH_GetHashOidTagByHMACOidTag(hashAlg);
        if (baseHashAlg == SEC_OID_UNKNOWN) {
            /* not an hmac either, reject the entry */
            return SEC_OID_UNKNOWN;
        }
    }
    return hashAlg;
}

static PRUintn
P12U_Init(char *dir, char *dbprefix, PRBool listonly)
{
    SECStatus rv;
    PK11_SetPasswordFunc(SECU_GetModulePassword);

    PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
    if (listonly && NSS_NoDB_Init("") == SECSuccess) {
        rv = SECSuccess;
    } else {
        rv = NSS_Initialize(dir, dbprefix, dbprefix, "secmod.db", 0);
    }
    if (rv != SECSuccess) {
        SECU_PrintPRandOSError(progName);
        exit(-1);
    }

    /* setup unicode callback functions */
    PORT_SetUCS2_ASCIIConversionFunction(p12u_ucs2_ascii_conversion_function);
    /* use the defaults for UCS4-UTF8 and UCS2-UTF8 */

    /* ciphers are already enabled by default, allow policy to work */
    /* p12u_EnableAllCiphers(); */

    return 0;
}

enum {
    opt_CertDir = 0,
    opt_TokenName,
    opt_Import,
    opt_SlotPWFile,
    opt_SlotPW,
    opt_List,
    opt_Nickname,
    opt_Export,
    opt_Raw,
    opt_P12FilePWFile,
    opt_P12FilePW,
    opt_DBPrefix,
    opt_Debug,
    opt_Cipher,
    opt_CertCipher,
    opt_KeyLength,
    opt_CertKeyLength,
    opt_Mac,
    opt_IgnoreIntegrity
};

static secuCommandFlag pk12util_options[] = {
    { /* opt_CertDir        */ 'd', PR_TRUE, 0, PR_FALSE },
    { /* opt_TokenName        */ 'h', PR_TRUE, 0, PR_FALSE },
    { /* opt_Import        */ 'i', PR_TRUE, 0, PR_FALSE },
    { /* opt_SlotPWFile        */ 'k', PR_TRUE, 0, PR_FALSE },
    { /* opt_SlotPW        */ 'K', PR_TRUE, 0, PR_FALSE },
    { /* opt_List              */ 'l', PR_TRUE, 0, PR_FALSE },
    { /* opt_Nickname        */ 'n', PR_TRUE, 0, PR_FALSE },
    { /* opt_Export        */ 'o', PR_TRUE, 0, PR_FALSE },
    { /* opt_Raw           */ 'r', PR_FALSE, 0, PR_FALSE },
    { /* opt_P12FilePWFile     */ 'w', PR_TRUE, 0, PR_FALSE },
    { /* opt_P12FilePW        */ 'W', PR_TRUE, 0, PR_FALSE },
    { /* opt_DBPrefix        */ 'P', PR_TRUE, 0, PR_FALSE },
    { /* opt_Debug        */ 'v', PR_FALSE, 0, PR_FALSE },
    { /* opt_Cipher        */ 'c', PR_TRUE, 0, PR_FALSE },
    { /* opt_CertCipher        */ 'C', PR_TRUE, 0, PR_FALSE },
    { /* opt_KeyLength         */ 'm', PR_TRUE, 0, PR_FALSE, "key_len" },
    { /* opt_CertKeyLength     */ 0, PR_TRUE, 0, PR_FALSE, "cert_key_len" },
    { /* opt_Mac               */ 'M', PR_TRUE, 0, PR_FALSE },
    { /* opt_IgnoreIntegrity   */ 'I', PR_FALSE, 0, PR_FALSE }
};

int
main(int argc, char **argv)
{
    secuPWData slotPw = { PW_NONE, NULL };
    secuPWData p12FilePw = { PW_NONE, NULL };
    PK11SlotInfo *slot;
    char *slotname = NULL;
    char *import_file = NULL;
    char *export_file = NULL;
    char *dbprefix = "";
    SECStatus rv;
    SECOidTag cipher = SEC_OID_AES_256_CBC;
    SECOidTag hash = SEC_OID_SHA256;
    SECOidTag certCipher = SEC_OID_AES_128_CBC;
    int keyLen = 0;
    int certKeyLen = 0;
    secuCommand pk12util;
    PRInt32 forceUnicode;
    PRBool ignoreIntegrity = PR_FALSE;

#ifdef _CRTDBG_MAP_ALLOC
    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
#endif

    pk12util.numCommands = 0;
    pk12util.commands = 0;
    pk12util.numOptions = sizeof(pk12util_options) / sizeof(secuCommandFlag);
    pk12util.options = pk12util_options;

    progName = strrchr(argv[0], '/');
    progName = progName ? progName + 1 : argv[0];

    rv = SECU_ParseCommandLine(argc, argv, progName, &pk12util);

    if (rv != SECSuccess)
        Usage();

    pk12_debugging = pk12util.options[opt_Debug].activated;

    if ((pk12util.options[opt_Import].activated +
         pk12util.options[opt_Export].activated +
         pk12util.options[opt_List].activated) != 1) {
        Usage();
    }

    if (pk12util.options[opt_Export].activated &&
        !pk12util.options[opt_Nickname].activated) {
        Usage();
    }

    rv = NSS_OptionGet(__NSS_PKCS12_DECODE_FORCE_UNICODE, &forceUnicode);
    if (rv != SECSuccess) {
        SECU_PrintError(progName,
                        "Failed to get NSS_PKCS12_DECODE_FORCE_UNICODE option");
        Usage();
    }
    pk12uForceUnicode = forceUnicode;

    slotname = SECU_GetOptionArg(&pk12util, opt_TokenName);

    import_file = (pk12util.options[opt_List].activated) ? SECU_GetOptionArg(&pk12util, opt_List)
                                                         : SECU_GetOptionArg(&pk12util, opt_Import);
    export_file = SECU_GetOptionArg(&pk12util, opt_Export);

    if (pk12util.options[opt_P12FilePWFile].activated) {
        p12FilePw.source = PW_FROMFILE;
        p12FilePw.data = PORT_Strdup(pk12util.options[opt_P12FilePWFile].arg);
    }

    if (pk12util.options[opt_P12FilePW].activated) {
        p12FilePw.source = PW_PLAINTEXT;
        p12FilePw.data = PORT_Strdup(pk12util.options[opt_P12FilePW].arg);
    }

    if (pk12util.options[opt_SlotPWFile].activated) {
        slotPw.source = PW_FROMFILE;
        slotPw.data = PORT_Strdup(pk12util.options[opt_SlotPWFile].arg);
    }

    if (pk12util.options[opt_SlotPW].activated) {
        slotPw.source = PW_PLAINTEXT;
        slotPw.data = PORT_Strdup(pk12util.options[opt_SlotPW].arg);
    }

    if (pk12util.options[opt_CertDir].activated) {
        SECU_ConfigDirectory(pk12util.options[opt_CertDir].arg);
    }
    if (pk12util.options[opt_DBPrefix].activated) {
        dbprefix = pk12util.options[opt_DBPrefix].arg;
    }
    if (pk12util.options[opt_Raw].activated) {
        dumpRawFile = PR_TRUE;
    }
    if (pk12util.options[opt_IgnoreIntegrity].activated) {
        ignoreIntegrity = PR_TRUE;
    }
    if (pk12util.options[opt_KeyLength].activated) {
        keyLen = atoi(pk12util.options[opt_KeyLength].arg);
    }
    if (pk12util.options[opt_CertKeyLength].activated) {
        certKeyLen = atoi(pk12util.options[opt_CertKeyLength].arg);
    }

    P12U_Init(SECU_ConfigDirectory(NULL), dbprefix,
              pk12util.options[opt_List].activated);

    if (!slotname || PL_strcmp(slotname, "internal") == 0)
        slot = PK11_GetInternalKeySlot();
    else
        slot = PK11_FindSlotByName(slotname);

    if (!slot) {
        SECU_PrintError(progName, "Invalid slot \"%s\"", slotname);
        pk12uErrno = PK12UERR_PK11GETSLOT;
        goto done;
    }

    if (pk12util.options[opt_Cipher].activated) {
        char *cipherString = pk12util.options[opt_Cipher].arg;

        cipher = PKCS12U_MapCipherFromString(cipherString, keyLen);
        /* We only want encryption PBE's. make sure we don't have
         * any MAC pbes */

        if (cipher == SEC_OID_UNKNOWN) {
            PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
            SECU_PrintError(progName, "Algorithm: \"%s\"", cipherString);
            pk12uErrno = PK12UERR_INVALIDALGORITHM;
            goto done;
        }
    }

    if (pk12util.options[opt_CertCipher].activated) {
        char *cipherString = pk12util.options[opt_CertCipher].arg;

        if (PORT_Strcasecmp(cipherString, "none") == 0) {
            certCipher = SEC_OID_UNKNOWN;
        } else {
            certCipher = PKCS12U_MapCipherFromString(cipherString, certKeyLen);
            /* If the user requested a cipher and we didn't find it, then
             * don't just silently not encrypt. */

            if (certCipher == SEC_OID_UNKNOWN) {
                PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
                SECU_PrintError(progName, "Algorithm: \"%s\"", cipherString);
                pk12uErrno = PK12UERR_INVALIDALGORITHM;
                goto done;
            }
        }
    }
    /* in FIPS mode default to encoding with pkcs5v2 for the MAC */
    if (PK11_IsFIPS()) {
        hash = SEC_OID_HMAC_SHA256;
    }
    if (pk12util.options[opt_Mac].activated) {
        char *hashString = pk12util.options[opt_Mac].arg;

        hash = PKCS12U_MapHashFromString(hashString);
        /* We don't support creating Mac-less pkcs 12 files */
        if (hash == SEC_OID_UNKNOWN) {
            PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
            SECU_PrintError(progName, "Algorithm: \"%s\"", hashString);
            pk12uErrno = PK12UERR_INVALIDALGORITHM;
            goto done;
        }
    }

    if (pk12util.options[opt_Import].activated) {
        P12U_ImportPKCS12Object(import_file, slot, &slotPw, &p12FilePw,
                                ignoreIntegrity);

    } else if (pk12util.options[opt_Export].activated) {
        P12U_ExportPKCS12Object(pk12util.options[opt_Nickname].arg,
                                export_file, slot, cipher, certCipher,
                                hash, &slotPw, &p12FilePw);

    } else if (pk12util.options[opt_List].activated) {
        P12U_ListPKCS12File(import_file, slot, &slotPw, &p12FilePw,
                            ignoreIntegrity);

    } else {
        Usage();
        pk12uErrno = PK12UERR_USAGE;
    }

done:
    if (import_file != NULL)
        PORT_ZFree(import_file, PL_strlen(import_file));
    if (export_file != NULL)
        PORT_ZFree(export_file, PL_strlen(export_file));
    if (slotPw.data != NULL)
        PORT_ZFree(slotPw.data, PL_strlen(slotPw.data));
    if (p12FilePw.data != NULL)
        PORT_ZFree(p12FilePw.data, PL_strlen(p12FilePw.data));
    if (slot)
        PK11_FreeSlot(slot);
    if (NSS_Shutdown() != SECSuccess) {
        pk12uErrno = 1;
    }
    PL_ArenaFinish();
    PR_Cleanup();
    return pk12uErrno;
}

Messung V0.5
C=95 H=80 G=87

¤ Dauer der Verarbeitung: 0.16 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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge