f65b513
/*
f65b513
   Copyright 2008 Red Hat, Inc.
f65b513
f65b513
   This program is free software; you can redistribute it and/or modify
f65b513
   it under the terms of the GNU General Public License as published by
f65b513
   the Free Software Foundation; either version 2 of the License, or
f65b513
   (at your option) any later version.
f65b513
  
f65b513
   This program is distributed in the hope that it will be useful,
f65b513
   but WITHOUT ANY WARRANTY; without even the implied warranty of
f65b513
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
f65b513
   GNU General Public License for more details.
f65b513
  
f65b513
   You should have received a copy of the GNU General Public License
f65b513
   along with this program; if not, write to the Free Software
f65b513
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
f65b513
   
f65b513
   In addition, as a special exception, Red Hat, Inc. gives permission
f65b513
   to link the code of this program with the OpenSSL library (or with
f65b513
   modified versions of OpenSSL that use the same license as OpenSSL),
f65b513
   and distribute linked combinations including the two. You must obey
f65b513
   the GNU General Public License in all respects for all of the code
f65b513
   used other than OpenSSL. If you modify this file, you may extend
f65b513
   this exception to your version of the file, but you are not
f65b513
   obligated to do so. If you do not wish to do so, delete this
f65b513
   exception statement from your version.
f65b513
f65b513
*/
f65b513
f65b513
/* Certificate processing utilities, based on code from Mozilla
f65b513
 * Network Security Services internal secutils static library.
f65b513
 */
f65b513
f65b513
/* ***** BEGIN LICENSE BLOCK *****
f65b513
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
f65b513
 *
f65b513
 * The contents of this file are subject to the Mozilla Public License Version
f65b513
 * 1.1 (the "License"); you may not use this file except in compliance with
f65b513
 * the License. You may obtain a copy of the License at
f65b513
 * http://www.mozilla.org/MPL/
f65b513
 *
f65b513
 * Software distributed under the License is distributed on an "AS IS" basis,
f65b513
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
f65b513
 * for the specific language governing rights and limitations under the
f65b513
 * License.
f65b513
 *
f65b513
 * The Original Code is the Netscape security libraries.
f65b513
 *
f65b513
 * The Initial Developer of the Original Code is
f65b513
 * Netscape Communications Corporation.
f65b513
 * Portions created by the Initial Developer are Copyright (C) 1994-2000
f65b513
 * the Initial Developer. All Rights Reserved.
f65b513
 *
f65b513
 * Contributor(s):
f65b513
 *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
f65b513
 *
f65b513
 * Alternatively, the contents of this file may be used under the terms of
f65b513
 * either the GNU General Public License Version 2 or later (the "GPL"), or
f65b513
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
f65b513
 * in which case the provisions of the GPL or the LGPL are applicable instead
f65b513
 * of those above. If you wish to allow use of your version of this file only
f65b513
 * under the terms of either the GPL or the LGPL, and not to allow others to
f65b513
 * use your version of this file under the terms of the MPL, indicate your
f65b513
 * decision by deleting the provisions above and replace them with the notice
f65b513
 * and other provisions required by the GPL or the LGPL. If you do not delete
f65b513
 * the provisions above, a recipient may use your version of this file under
f65b513
 * the terms of any one of the MPL, the GPL or the LGPL.
f65b513
 *
f65b513
 * ***** END LICENSE BLOCK ***** */
f65b513
f65b513
/*
f65b513
 * The exported function here is PEMUTIL_PEM_read_X509. A function like
f65b513
 * this belongs in nss_compat_ossl. Elio Maldonado <emaldona@redhat.com> 
f65b513
 */
f65b513
f65b513
#include <cert.h>
f65b513
#include <certt.h>
f65b513
#include <nspr.h>
f65b513
#include <seccomon.h>
f65b513
#include <base64.h>
f65b513
#include <assert.h>
f65b513
f65b513
#define TIME_BUF_SIZE 100
f65b513
f65b513
/* decode a SECItem containing either a SEC_ASN1_GENERALIZED_TIME 
f65b513
   or a SEC_ASN1_UTC_TIME */
f65b513
extern SECStatus DER_DecodeTimeChoice(PRTime* output, const SECItem* input);
f65b513
f65b513
f65b513
/* Loads the contents of a file into a SECItem.
f65b513
 * Code is from the NSS security utilities.
f65b513
 */
f65b513
static SECStatus FileToItem(SECItem *dst, PRFileDesc *src)
f65b513
{
f65b513
    PRFileInfo info;
f65b513
    PRInt32 numBytes;
f65b513
    PRStatus prStatus;
f65b513
f65b513
    prStatus = PR_GetOpenFileInfo(src, &info;;
f65b513
f65b513
    if (prStatus != PR_SUCCESS) {
eff035f
        return SECFailure;
f65b513
    }
f65b513
f65b513
    /* XXX workaround for 3.1, not all utils zero dst before sending */
f65b513
    dst->data = 0;
f65b513
    if (!SECITEM_AllocItem(NULL, dst, info.size))
eff035f
        goto loser;
f65b513
f65b513
    numBytes = PR_Read(src, dst->data, info.size);
f65b513
    if (numBytes != info.size)
f65b513
        goto loser;
f65b513
f65b513
    return SECSuccess;
f65b513
loser:
f65b513
    SECITEM_FreeItem(dst, PR_FALSE);
f65b513
    dst->data = NULL;
f65b513
    return SECFailure;
f65b513
}
f65b513
f65b513
/* Load a DER encoding into a SECItem.
f65b513
 * Code is from the NSS security utilities.
f65b513
 */
f65b513
static SECStatus ReadDERFromFile(SECItem *der, PRFileDesc *inFile, PRBool ascii)
f65b513
{
f65b513
    SECStatus rv;
f65b513
    if (ascii) {
eff035f
        /* First convert ascii to binary */
eff035f
        SECItem filedata;
eff035f
        char *asc, *body;
eff035f
    
eff035f
        /* Read in ascii data */
eff035f
        rv = FileToItem(&filedata, inFile);
eff035f
        asc = (char *)filedata.data;
eff035f
        if (!asc) {
eff035f
            return SECFailure;
eff035f
        }
eff035f
    
c0b5ca0
        body = strstr(asc, "-----BEGIN CERTIFICATE");
c0b5ca0
        if (!body) body = strstr(asc, "-----BEGIN X509 CERTIFICATE");
eff035f
        /* check for headers and trailers and remove them */
c0b5ca0
        if (body) {
eff035f
            char *trailer = NULL;
eff035f
            asc = body;
eff035f
            body = PORT_Strchr(body, '\n');
eff035f
            if (!body)
eff035f
                body = PORT_Strchr(asc, '\r'); /* maybe this is a MAC file */
eff035f
            if (body)
eff035f
                trailer = strstr(++body, "-----END");
eff035f
            if (trailer != NULL) {
eff035f
                *trailer = '\0';
eff035f
            } else {
eff035f
                /*printf("input has header but no trailer\n");*/
eff035f
                PORT_Free(filedata.data);
eff035f
                return SECFailure;
eff035f
           }
eff035f
        } else {
eff035f
            body = asc;
eff035f
        }
eff035f
         
eff035f
        /* Convert to binary */
eff035f
        rv = ATOB_ConvertAsciiToItem(der, body);
eff035f
        if (rv) {
eff035f
            /* printf("ATOB_ConvertAsciiToItem failed\n");*/
eff035f
            PORT_Free(filedata.data);
eff035f
            return SECFailure;
eff035f
        }
eff035f
    
eff035f
        PORT_Free(filedata.data);
f65b513
    } else {
eff035f
        /* Read in binary der */
eff035f
        rv = FileToItem(der, inFile);
eff035f
        if (rv) {
eff035f
            return SECFailure;
eff035f
        }
f65b513
    }
f65b513
    return SECSuccess;
f65b513
}
f65b513
f65b513
f65b513
/* Return a certificate structure from a pem-encoded cert in a file; 
f65b513
 * or NULL on failure. Semantics similar to an OpenSSL
f65b513
 * PEM_read_X509(fp, NULL, NULL, NULL); call
f65b513
 */
f65b513
CERTCertificate *
f65b513
PEMUTIL_PEM_read_X509(const char *filename)
f65b513
{
f65b513
    CERTCertificate *cert = NULL;
f65b513
    PRFileDesc *fd = NULL;
f65b513
    SECItem derCert;
f65b513
f65b513
    fd = PR_Open(filename, PR_RDONLY, 0);
f65b513
    if (!fd) return NULL;
f65b513
f65b513
    /* Read in a DER from a file, it is ascii */
f65b513
    if (SECSuccess != ReadDERFromFile(&derCert, fd, PR_TRUE))
eff035f
        goto cleanup;
f65b513
   
f65b513
    /* create a temporary cert in the database */
f65b513
    cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), 
eff035f
            &derCert, NULL, PR_FALSE, PR_FALSE);
f65b513
               /* noNickname, notPerm, noCopy */
f65b513
 cleanup:
f65b513
    if (fd) PR_Close(fd);
f65b513
f65b513
    return cert;
f65b513
}