Blame SOURCES/secutil.c

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