Blame SOURCES/secutil.c

4418f4
/*
4418f4
   Copyright 2005 Red Hat, Inc.
4418f4
4418f4
   This program is free software; you can redistribute it and/or modify
4418f4
   it under the terms of the GNU General Public License as published by
4418f4
   the Free Software Foundation; either version 2 of the License, or
4418f4
   (at your option) any later version.
4418f4
  
4418f4
   This program is distributed in the hope that it will be useful,
4418f4
   but WITHOUT ANY WARRANTY; without even the implied warranty of
4418f4
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
4418f4
   GNU General Public License for more details.
4418f4
  
4418f4
   You should have received a copy of the GNU General Public License
4418f4
   along with this program; if not, write to the Free Software
4418f4
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
4418f4
   
4418f4
   In addition, as a special exception, Red Hat, Inc. gives permission
4418f4
   to link the code of this program with the OpenSSL library (or with
4418f4
   modified versions of OpenSSL that use the same license as OpenSSL),
4418f4
   and distribute linked combinations including the two. You must obey
4418f4
   the GNU General Public License in all respects for all of the code
4418f4
   used other than OpenSSL. If you modify this file, you may extend
4418f4
   this exception to your version of the file, but you are not
4418f4
   obligated to do so. If you do not wish to do so, delete this
4418f4
   exception statement from your version.
4418f4
4418f4
*/
4418f4
4418f4
/* ***** BEGIN LICENSE BLOCK *****
4418f4
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4418f4
 *
4418f4
 * The contents of this file are subject to the Mozilla Public License Version
4418f4
 * 1.1 (the "License"); you may not use this file except in compliance with
4418f4
 * the License. You may obtain a copy of the License at
4418f4
 * http://www.mozilla.org/MPL/
4418f4
 *
4418f4
 * Software distributed under the License is distributed on an "AS IS" basis,
4418f4
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
4418f4
 * for the specific language governing rights and limitations under the
4418f4
 * License.
4418f4
 *
4418f4
 * The Original Code is the Netscape security libraries.
4418f4
 *
4418f4
 * The Initial Developer of the Original Code is
4418f4
 * Netscape Communications Corporation.
4418f4
 * Portions created by the Initial Developer are Copyright (C) 1994-2000
4418f4
 * the Initial Developer. All Rights Reserved.
4418f4
 *
4418f4
 * Contributor(s):
4418f4
 *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
4418f4
 *
4418f4
 * Alternatively, the contents of this file may be used under the terms of
4418f4
 * either the GNU General Public License Version 2 or later (the "GPL"), or
4418f4
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
4418f4
 * in which case the provisions of the GPL or the LGPL are applicable instead
4418f4
 * of those above. If you wish to allow use of your version of this file only
4418f4
 * under the terms of either the GPL or the LGPL, and not to allow others to
4418f4
 * use your version of this file under the terms of the MPL, indicate your
4418f4
 * decision by deleting the provisions above and replace them with the notice
4418f4
 * and other provisions required by the GPL or the LGPL. If you do not delete
4418f4
 * the provisions above, a recipient may use your version of this file under
4418f4
 * the terms of any one of the MPL, the GPL or the LGPL.
4418f4
 *
4418f4
 * ***** END LICENSE BLOCK ***** */
4418f4
/*
4418f4
** secutil.c - various functions used by security stuff
4418f4
** 
4418f4
** This code comes from the NSS internal library used by the
4418f4
** the NSS security tools.
4418f4
**
4418f4
*/
4418f4
4418f4
#include <prtypes.h>
4418f4
#include <prtime.h>
4418f4
#include <prlong.h>
4418f4
#include <prerror.h>
4418f4
#include <prprf.h>
4418f4
#include <plgetopt.h>
4418f4
#include <prenv.h>
4418f4
#include <prnetdb.h>
4418f4
4418f4
#include <cryptohi.h>
4418f4
#include <secpkcs7.h>
4418f4
#include <secpkcs5.h>
4418f4
#include <stdarg.h>
4418f4
4418f4
#include <sys/stat.h>
4418f4
#include <errno.h>
4418f4
4418f4
#include <unistd.h>
4418f4
4418f4
/* for SEC_TraverseNames */
4418f4
#include <cert.h>
4418f4
#include <certt.h>
4418f4
#include <certdb.h>
4418f4
4418f4
#include <secmod.h>
4418f4
#include <pk11func.h>
4418f4
#include <secoid.h>
4418f4
4418f4
#include "secutil.h"
4418f4
4418f4
#if(0)
4418f4
static char consoleName[] =  {
4418f4
    "/dev/tty"
4418f4
};
4418f4
#endif
4418f4
4418f4
char *
4418f4
SECU_GetString(int16 error_number)
4418f4
{
4418f4
4418f4
    static char errString[80];
4418f4
    sprintf(errString, "Unknown error string (%d)", error_number);
4418f4
    return errString;
4418f4
}
4418f4
4418f4
static void 
4418f4
SECU_PrintErrMsg(FILE *out, int level, char *progName, char *msg, va_list args)
4418f4
{
4418f4
    PRErrorCode err = PORT_GetError();
4418f4
    const char * errString = PORT_ErrorToString(err);
4418f4
4418f4
    SECU_Indent(out, level);
4418f4
    fprintf(out, "%s: ", progName);
4418f4
    vfprintf(out, msg, args);
4418f4
    if (errString != NULL && PORT_Strlen(errString) > 0)
4418f4
    fprintf(out, ": %s\n", errString);
4418f4
    else
4418f4
    fprintf(out, ": error %d\n", (int)err);
4418f4
}
4418f4
4418f4
void SECU_PrintError(char *progName, char *msg, ...)
4418f4
{
4418f4
    va_list args;
4418f4
4418f4
    va_start(args, msg);
4418f4
    SECU_PrintErrMsg(stderr, 0, progName, msg, args);
4418f4
    va_end(args);
4418f4
}
4418f4
4418f4
#define INDENT_MULT 4
4418f4
void
4418f4
SECU_Indent(FILE *out, int level)
4418f4
{
4418f4
    int i;
4418f4
4418f4
    for (i = 0; i < level; i++) {
4418f4
    fprintf(out, "    ");
4418f4
    }
4418f4
}
4418f4
4418f4
static void secu_Newline(FILE *out)
4418f4
{
4418f4
    fprintf(out, "\n");
4418f4
}
4418f4
4418f4
void
4418f4
SECU_PrintAsHex(FILE *out, SECItem *data, const char *m, int level)
4418f4
{
4418f4
    unsigned i;
4418f4
    int column;
4418f4
    PRBool isString     = PR_TRUE;
4418f4
    PRBool isWhiteSpace = PR_TRUE;
4418f4
    PRBool printedHex   = PR_FALSE;
4418f4
    unsigned int limit = 15;
4418f4
4418f4
    if ( m ) {
4418f4
        SECU_Indent(out, level); fprintf(out, "%s:\n", m);
4418f4
        level++;
4418f4
    }
4418f4
    
4418f4
    SECU_Indent(out, level); column = level*INDENT_MULT;
4418f4
    if (!data->len) {
4418f4
        fprintf(out, "(empty)\n");
4418f4
        return;
4418f4
    }
4418f4
    /* take a pass to see if it's all printable. */
4418f4
    for (i = 0; i < data->len; i++) {
4418f4
        unsigned char val = data->data[i];
4418f4
        if (!val || !isprint(val)) {
4418f4
            isString = PR_FALSE;
4418f4
            break;
4418f4
        }
4418f4
        if (isWhiteSpace && !isspace(val)) {
4418f4
            isWhiteSpace = PR_FALSE;
4418f4
        }
4418f4
    }
4418f4
4418f4
    /* Short values, such as bit strings (which are printed with this
4418f4
    ** function) often look like strings, but we want to see the bits.
4418f4
    ** so this test assures that short values will be printed in hex,
4418f4
    ** perhaps in addition to being printed as strings.
4418f4
    ** The threshold size (4 bytes) is arbitrary.
4418f4
    */
4418f4
    if (!isString || data->len <= 4) {
4418f4
        for (i = 0; i < data->len; i++) {
4418f4
            if (i != data->len - 1) {
4418f4
                fprintf(out, "%02x:", data->data[i]);
4418f4
                column += 3;
4418f4
            } else {
4418f4
                fprintf(out, "%02x", data->data[i]);
4418f4
                column += 2;
4418f4
                break;
4418f4
            }
4418f4
            if (column > 76 || (i % 16 == limit)) {
4418f4
            	secu_Newline(out);
4418f4
            	SECU_Indent(out, level); 
4418f4
            	column = level*INDENT_MULT;
4418f4
            	limit = i % 16;
4418f4
            }
4418f4
        }
4418f4
        printedHex = PR_TRUE;
4418f4
    }
4418f4
	if (isString && !isWhiteSpace) {
4418f4
	    if (printedHex != PR_FALSE) {
4418f4
	        secu_Newline(out);
4418f4
	        SECU_Indent(out, level); column = level*INDENT_MULT;
4418f4
	    }
4418f4
	    for (i = 0; i < data->len; i++) {
4418f4
	        unsigned char val = data->data[i];
4418f4
	
4418f4
	        if (val) {
4418f4
	        	fprintf(out,"%c",val);
4418f4
	        	column++;
4418f4
	        } else {
4418f4
	        	column = 77;
4418f4
	        }
4418f4
	        if (column > 76) {
4418f4
	        	secu_Newline(out);
4418f4
	            SECU_Indent(out, level); column = level*INDENT_MULT;
4418f4
	        }
4418f4
	    }
4418f4
	}
4418f4
        
4418f4
    if (column != level*INDENT_MULT) {
4418f4
    	secu_Newline(out);
4418f4
    }
4418f4
}
4418f4
4418f4
/* This function does NOT expect a DER type and length. */
4418f4
SECOidTag
4418f4
SECU_PrintObjectID(FILE *out, SECItem *oid, char *m, int level)
4418f4
{
4418f4
    SECOidData *oiddata;
4418f4
    char *oidString = NULL;
4418f4
    
4418f4
    oiddata = SECOID_FindOID(oid);
4418f4
    if (oiddata != NULL) {
4418f4
	    const char *name = oiddata->desc;
4418f4
	    SECU_Indent(out, level);
4418f4
	    if (m != NULL)
4418f4
	        fprintf(out, "%s: ", m);
4418f4
	    fprintf(out, "%s\n", name);
4418f4
	    return oiddata->offset;
4418f4
    } 
4418f4
    oidString = CERT_GetOidString(oid);
4418f4
    if (oidString) {
4418f4
	    SECU_Indent(out, level);
4418f4
	    if (m != NULL)
4418f4
	        fprintf(out, "%s: ", m);
4418f4
	    fprintf(out, "%s\n", oidString);
4418f4
	    PR_smprintf_free(oidString);
4418f4
	    return SEC_OID_UNKNOWN;
4418f4
    }
4418f4
    SECU_PrintAsHex(out, oid, m, level);
4418f4
    return SEC_OID_UNKNOWN;
4418f4
}
4418f4
4418f4
void
4418f4
SECU_PrintSystemError(char *progName, char *msg, ...)
4418f4
{
4418f4
    va_list args;
4418f4
4418f4
    va_start(args, msg);
4418f4
    fprintf(stderr, "%s: ", progName);
4418f4
    vfprintf(stderr, msg, args);
4418f4
    fprintf(stderr, ": %s\n", strerror(errno));
4418f4
    va_end(args);
4418f4
}
4418f4
4418f4
#if(0)
4418f4
static void
4418f4
secu_ClearPassword(char *p)
4418f4
{
4418f4
    if (p) {
4418f4
	PORT_Memset(p, 0, PORT_Strlen(p));
4418f4
	PORT_Free(p);
4418f4
    }
4418f4
}
4418f4
4418f4
char *
4418f4
SECU_GetPasswordString(void *arg, char *prompt)
4418f4
{
4418f4
    char *p = NULL;
4418f4
    FILE *input, *output;
4418f4
4418f4
    /* open terminal */
4418f4
    input = fopen(consoleName, "r");
4418f4
    if (input == NULL) {
4418f4
	fprintf(stderr, "Error opening input terminal for read\n");
4418f4
	return NULL;
4418f4
    }
4418f4
4418f4
    output = fopen(consoleName, "w");
4418f4
    if (output == NULL) {
4418f4
	fprintf(stderr, "Error opening output terminal for write\n");
4418f4
	return NULL;
4418f4
    }
4418f4
4418f4
    p = SEC_GetPassword (input, output, prompt, SEC_BlindCheckPassword);
4418f4
        
4418f4
    fclose(input);
4418f4
    fclose(output);
4418f4
4418f4
    return p;
4418f4
}
4418f4
#endif
4418f4
4418f4
4418f4
/*
4418f4
 *  p a s s w o r d _ h a r d c o d e 
4418f4
 *
4418f4
 *  A function to use the password passed in the -f(pwfile) argument
4418f4
 *  of the command line.  
4418f4
 *  After use once, null it out otherwise PKCS11 calls us forever.?
4418f4
 *
4418f4
 */
4418f4
char *
4418f4
SECU_FilePasswd(PK11SlotInfo *slot, PRBool retry, void *arg)
4418f4
{
4418f4
    char* phrases, *phrase;
4418f4
    PRFileDesc *fd;
4418f4
    PRInt32 nb;
4418f4
    const char *pwFile = (const char *)arg;
4418f4
    int i;
4418f4
    const long maxPwdFileSize = 4096;
4418f4
    char* tokenName = NULL;
4418f4
    int tokenLen = 0;
4418f4
    
4418f4
    if (!pwFile) {
4418f4
	    return 0;
4418f4
    }
4418f4
4418f4
    if (retry) {
4418f4
    	return 0;  /* no good retrying - the files contents will be the same */
4418f4
    }
4418f4
4418f4
    phrases = PORT_ZAlloc(maxPwdFileSize);
4418f4
4418f4
    if (!phrases) {
4418f4
        return 0; /* out of memory */
4418f4
    }
4418f4
 
4418f4
    fd = PR_Open(pwFile, PR_RDONLY, 0);
4418f4
    if (!fd) {
4418f4
	    fprintf(stderr, "No password file \"%s\" exists.\n", pwFile);
4418f4
        PORT_Free(phrases);
4418f4
	    return NULL;
4418f4
    }
4418f4
4418f4
    nb = PR_Read(fd, phrases, maxPwdFileSize);
4418f4
  
4418f4
    PR_Close(fd);
4418f4
4418f4
    if (nb == 0) {
4418f4
        fprintf(stderr,"password file contains no data\n");
4418f4
        PORT_Free(phrases);
4418f4
        return NULL;
4418f4
    }
4418f4
4418f4
    if (slot) {
4418f4
        tokenName = PK11_GetTokenName(slot);
4418f4
        if (tokenName) {
4418f4
            tokenLen = PORT_Strlen(tokenName);
4418f4
        }
4418f4
    }
4418f4
    i = 0;
4418f4
    do {
4418f4
        int startphrase = i;
4418f4
        int phraseLen;
4418f4
4418f4
        /* handle the Windows EOL case */
4418f4
        while (phrases[i] != '\r' && phrases[i] != '\n' && i < nb) i++;
4418f4
        /* terminate passphrase */
4418f4
        phrases[i++] = '\0';
4418f4
        /* clean up any EOL before the start of the next passphrase */
4418f4
        while ( (i
4418f4
            phrases[i++] = '\0';
4418f4
        }
4418f4
        /* now analyze the current passphrase */
4418f4
        phrase = &phrases[startphrase];
4418f4
        if (!tokenName)
4418f4
            break;
4418f4
        if (PORT_Strncmp(phrase, tokenName, tokenLen)) continue;
4418f4
        phraseLen = PORT_Strlen(phrase);
4418f4
        if (phraseLen < (tokenLen+1)) continue;
4418f4
        if (phrase[tokenLen] != ':') continue;
4418f4
        phrase = &phrase[tokenLen+1];
4418f4
        break;
4418f4
4418f4
    } while (i
4418f4
4418f4
    phrase = PORT_Strdup((char*)phrase);
4418f4
    PORT_Free(phrases);
4418f4
    return phrase;
4418f4
}
4418f4
4418f4
char *
4418f4
SECU_GetModulePassword(PK11SlotInfo *slot, PRBool retry, void *arg) 
4418f4
{
4418f4
#if(0)
4418f4
    char prompt[255];
4418f4
#endif
4418f4
    secuPWData *pwdata = (secuPWData *)arg;
4418f4
    secuPWData pwnull = { PW_NONE, 0 };
4418f4
    secuPWData pwxtrn = { PW_EXTERNAL, "external" };
4418f4
    char *pw;
4418f4
4418f4
    if (pwdata == NULL)
4418f4
        pwdata = &pwnull;
4418f4
4418f4
    if (PK11_ProtectedAuthenticationPath(slot)) {
4418f4
        pwdata = &pwxtrn;
4418f4
    }
4418f4
    if (retry && pwdata->source != PW_NONE) {
4418f4
        PR_fprintf(PR_STDERR, "Incorrect password/PIN entered.\n");
4418f4
        return NULL;
4418f4
    }
4418f4
4418f4
    switch (pwdata->source) {
4418f4
#if(0)
4418f4
    case PW_NONE:
4418f4
        sprintf(prompt, "Enter Password or Pin for \"%s\":",
4418f4
	            PK11_GetTokenName(slot));
4418f4
        return SECU_GetPasswordString(NULL, prompt);
4418f4
#endif
4418f4
4418f4
    case PW_FROMFILE:
4418f4
	    /* Instead of opening and closing the file every time, get the pw
4418f4
	     * once, then keep it in memory (duh).
4418f4
	     */
4418f4
	    pw = SECU_FilePasswd(slot, retry, pwdata->data);
4418f4
	    pwdata->source = PW_PLAINTEXT;
4418f4
	    pwdata->data = PL_strdup(pw);
4418f4
	    /* it's already been dup'ed */
4418f4
	    return pw;
4418f4
#if(0)
4418f4
    case PW_EXTERNAL:
4418f4
        sprintf(prompt, 
4418f4
	            "Press Enter, then enter PIN for \"%s\" on external device.\n",
4418f4
                PK11_GetTokenName(slot));
4418f4
        (void) SECU_GetPasswordString(NULL, prompt);
4418f4
    	/* Fall Through */
4418f4
#endif
4418f4
   case PW_PLAINTEXT:
4418f4
	    return PL_strdup(pwdata->data);
4418f4
    default:
4418f4
	    break;
4418f4
    }
4418f4
4418f4
    PR_fprintf(PR_STDERR, "Password check failed:  No password found.\n");
4418f4
    return NULL;
4418f4
}
4418f4
4418f4
/*
4418f4
 * Password callback so the user is not prompted to enter the password
4418f4
 * after the server starts.
4418f4
 */
4418f4
char *SECU_NoPassword(PK11SlotInfo *slot, PRBool retry, void *arg)
4418f4
{
4418f4
    return NULL;
4418f4
}
4418f4
4418f4
SECStatus
4418f4
secu_StdinToItem(SECItem *dst)
4418f4
{
4418f4
    unsigned char buf[1000];
4418f4
    PRInt32 numBytes;
4418f4
    PRBool notDone = PR_TRUE;
4418f4
4418f4
    dst->len = 0;
4418f4
    dst->data = NULL;
4418f4
4418f4
    while (notDone) {
4418f4
    numBytes = PR_Read(PR_STDIN, buf, sizeof(buf));
4418f4
4418f4
    if (numBytes < 0) {
4418f4
        return SECFailure;
4418f4
    }
4418f4
4418f4
    if (numBytes == 0)
4418f4
        break;
4418f4
4418f4
    if (dst->data) {
4418f4
        unsigned char * p = dst->data;
4418f4
        dst->data = (unsigned char*)PORT_Realloc(p, dst->len + numBytes);
4418f4
        if (!dst->data) {
4418f4
            PORT_Free(p);
4418f4
        }
4418f4
    } else {
4418f4
        dst->data = (unsigned char*)PORT_Alloc(numBytes);
4418f4
    }
4418f4
    if (!dst->data) {
4418f4
        return SECFailure;
4418f4
    }
4418f4
    PORT_Memcpy(dst->data + dst->len, buf, numBytes);
4418f4
    dst->len += numBytes;
4418f4
    }
4418f4
4418f4
    return SECSuccess;
4418f4
}
4418f4
4418f4
SECStatus
4418f4
SECU_FileToItem(SECItem *dst, PRFileDesc *src)
4418f4
{
4418f4
    PRFileInfo info;
4418f4
    PRInt32 numBytes;
4418f4
    PRStatus prStatus;
4418f4
4418f4
    if (src == PR_STDIN)
4418f4
        return secu_StdinToItem(dst);
4418f4
4418f4
    prStatus = PR_GetOpenFileInfo(src, &info;;
4418f4
4418f4
    if (prStatus != PR_SUCCESS) {
4418f4
        PORT_SetError(SEC_ERROR_IO);
4418f4
        return SECFailure;
4418f4
    }
4418f4
4418f4
    /* XXX workaround for 3.1, not all utils zero dst before sending */
4418f4
    dst->data = 0;
4418f4
    if (!SECITEM_AllocItem(NULL, dst, info.size))
4418f4
        goto loser;
4418f4
4418f4
    numBytes = PR_Read(src, dst->data, info.size);
4418f4
    if (numBytes != info.size) {
4418f4
        PORT_SetError(SEC_ERROR_IO);
4418f4
        goto loser;
4418f4
    }
4418f4
4418f4
    return SECSuccess;
4418f4
loser:
4418f4
    SECITEM_FreeItem(dst, PR_FALSE);
4418f4
    dst->data = NULL;
4418f4
    return SECFailure;
4418f4
}
4418f4
4418f4
SECStatus
4418f4
SECU_TextFileToItem(SECItem *dst, PRFileDesc *src)
4418f4
{
4418f4
    PRFileInfo info;
4418f4
    PRInt32 numBytes;
4418f4
    PRStatus prStatus;
4418f4
    unsigned char *buf;
4418f4
4418f4
    if (src == PR_STDIN)
4418f4
	return secu_StdinToItem(dst);
4418f4
4418f4
    prStatus = PR_GetOpenFileInfo(src, &info;;
4418f4
4418f4
    if (prStatus != PR_SUCCESS) {
4418f4
	PORT_SetError(SEC_ERROR_IO);
4418f4
	return SECFailure;
4418f4
    }
4418f4
4418f4
    buf = (unsigned char*)PORT_Alloc(info.size);
4418f4
    if (!buf)
4418f4
	return SECFailure;
4418f4
4418f4
    numBytes = PR_Read(src, buf, info.size);
4418f4
    if (numBytes != info.size) {
4418f4
	PORT_SetError(SEC_ERROR_IO);
4418f4
	goto loser;
4418f4
    }
4418f4
4418f4
    if (buf[numBytes-1] == '\n') numBytes--;
4418f4
#ifdef _WINDOWS
4418f4
    if (buf[numBytes-1] == '\r') numBytes--;
4418f4
#endif
4418f4
4418f4
    /* XXX workaround for 3.1, not all utils zero dst before sending */
4418f4
    dst->data = 0;
4418f4
    if (!SECITEM_AllocItem(NULL, dst, numBytes))
4418f4
	goto loser;
4418f4
4418f4
    memcpy(dst->data, buf, numBytes);
4418f4
4418f4
    PORT_Free(buf);
4418f4
    return SECSuccess;
4418f4
loser:
4418f4
    PORT_Free(buf);
4418f4
    return SECFailure;
4418f4
}
4418f4
4418f4
SECStatus
4418f4
SECU_ReadDERFromFile(SECItem *der, PRFileDesc *inFile, PRBool ascii)
4418f4
{
4418f4
    SECStatus rv;
4418f4
    if (ascii) {
4418f4
    /* First convert ascii to binary */
4418f4
    SECItem filedata;
4418f4
    char *asc, *body;
4418f4
4418f4
    /* Read in ascii data */
4418f4
    rv = SECU_FileToItem(&filedata, inFile);
4418f4
    asc = (char *)filedata.data;
4418f4
    if (!asc) {
4418f4
        fprintf(stderr, "unable to read data from input file\n");
4418f4
        return SECFailure;
4418f4
    }
4418f4
4418f4
    /* check for headers and trailers and remove them */
4418f4
    if ((body = strstr(asc, "-----BEGIN")) != NULL) {
4418f4
        char *trailer = NULL;
4418f4
        asc = body;
4418f4
        body = PORT_Strchr(body, '\n');
4418f4
        if (!body)
4418f4
            body = PORT_Strchr(asc, '\r'); /* maybe this is a MAC file */
4418f4
        if (body)
4418f4
            trailer = strstr(++body, "-----END");
4418f4
        if (trailer != NULL) {
4418f4
            *trailer = '\0';
4418f4
        } else {
4418f4
            fprintf(stderr, "input has header but no trailer\n");
4418f4
            PORT_Free(filedata.data);
4418f4
            return SECFailure;
4418f4
        }
4418f4
    } else {
4418f4
        body = asc;
4418f4
    }
4418f4
     
4418f4
    /* Convert to binary */
4418f4
    rv = ATOB_ConvertAsciiToItem(der, body);
4418f4
    if (rv) {
4418f4
        fprintf(stderr, "error converting ascii to binary (%d)\n",
4418f4
            PORT_GetError());
4418f4
        PORT_Free(filedata.data);
4418f4
        return SECFailure;
4418f4
    }
4418f4
4418f4
    PORT_Free(filedata.data);
4418f4
    } else {
4418f4
        /* Read in binary der */
4418f4
        rv = SECU_FileToItem(der, inFile);
4418f4
        if (rv) {
4418f4
            fprintf(stderr, "error converting der (%d)\n", 
4418f4
                PORT_GetError());
4418f4
            return SECFailure;
4418f4
        }
4418f4
    }
4418f4
    return SECSuccess;
4418f4
}
4418f4
4418f4
/* Encodes and adds extensions to the CRL or CRL entries. */
4418f4
SECStatus 
4418f4
SECU_EncodeAndAddExtensionValue(PRArenaPool *arena, void *extHandle, 
4418f4
                                void *value, PRBool criticality, int extenType, 
4418f4
                                EXTEN_EXT_VALUE_ENCODER EncodeValueFn)
4418f4
{
4418f4
    SECItem encodedValue;
4418f4
    SECStatus rv;
4418f4
4418f4
    encodedValue.data = NULL;
4418f4
    encodedValue.len = 0;
4418f4
    do {
4418f4
        rv = (*EncodeValueFn)(arena, value, &encodedValue);
4418f4
        if (rv != SECSuccess)
4418f4
            break;
4418f4
4418f4
        rv = CERT_AddExtension(extHandle, extenType, &encodedValue,
4418f4
                               criticality, PR_TRUE);
4418f4
        if (rv != SECSuccess)
4418f4
            break;
4418f4
        
4418f4
    } while (0);
4418f4
4418f4
    return (rv);
4418f4
}
4418f4
4418f4
/* Caller ensures that dst is at least item->len*2+1 bytes long */
4418f4
void
4418f4
SECU_SECItemToHex(const SECItem * item, char * dst)
4418f4
{
4418f4
    if (dst && item && item->data) {
4418f4
        unsigned char * src = item->data;
4418f4
        unsigned int    len = item->len;
4418f4
        for (; len > 0; --len, dst += 2) {
4418f4
            sprintf(dst, "%02x", *src++);
4418f4
        }
4418f4
        *dst = '\0';
4418f4
    }
4418f4
}
4418f4
4418f4
static unsigned char nibble(char c) {
4418f4
    c = PORT_Tolower(c);
4418f4
    return ( c >= '0' && c <= '9') ? c - '0' :
4418f4
           ( c >= 'a' && c <= 'f') ? c - 'a' +10 : -1;
4418f4
}
4418f4
4418f4
SECStatus
4418f4
SECU_SECItemHexStringToBinary(SECItem* srcdest)
4418f4
{
4418f4
    int i;
4418f4
4418f4
    if (!srcdest) {
4418f4
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
4418f4
        return SECFailure;
4418f4
    }
4418f4
    if (srcdest->len < 4 || (srcdest->len % 2) ) {
4418f4
        /* too short to convert, or even number of characters */
4418f4
        PORT_SetError(SEC_ERROR_BAD_DATA);
4418f4
        return SECFailure;
4418f4
    }
4418f4
    if (PORT_Strncasecmp((const char*)srcdest->data, "0x", 2)) {
4418f4
        /* wrong prefix */
4418f4
        PORT_SetError(SEC_ERROR_BAD_DATA);
4418f4
        return SECFailure;
4418f4
    }
4418f4
4418f4
    /* 1st pass to check for hex characters */
4418f4
    for (i=2; i<srcdest->len; i++) {
4418f4
        char c = PORT_Tolower(srcdest->data[i]);
4418f4
        if (! ( ( c >= '0' && c <= '9') ||
4418f4
                ( c >= 'a' && c <= 'f')
4418f4
              ) ) {
4418f4
            PORT_SetError(SEC_ERROR_BAD_DATA);
4418f4
            return SECFailure;
4418f4
        }
4418f4
    }
4418f4
4418f4
    /* 2nd pass to convert */
4418f4
    for (i=2; i<srcdest->len; i+=2) {
4418f4
        srcdest->data[(i-2)/2] = (nibble(srcdest->data[i]) << 4) +
4418f4
                                 nibble(srcdest->data[i+1]);
4418f4
    }
4418f4
4418f4
    /* adjust length */
4418f4
    srcdest->len -= 2;
4418f4
    srcdest->len /= 2;
4418f4
    return SECSuccess;
4418f4
}