parse_certificate_files.c

Go to the documentation of this file.
00001 /* parse_certificate_files.c  --  Parses PEM or PKCS12 formatted cert. files
00002  *
00003  *  GPLv2 only - Copyright (C) 2008 - 2010
00004  *               David Sommerseth <dazo@users.sourceforge.net>
00005  *
00006  *  This program is free software; you can redistribute it and/or
00007  *  modify it under the terms of the GNU General Public License
00008  *  as published by the Free Software Foundation; version 2
00009  *  of the License.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00019  *
00020  */
00021 
00032 #ifdef HAVE_OPENSSL
00033 #include <stdio.h>
00034 #include <string.h>
00035 #include <assert.h>
00036 
00037 #include <openssl/ssl.h>
00038 #include <openssl/pkcs12.h>
00039 #include <openssl/evp.h>
00040 #include <openssl/err.h>
00041 
00042 #include <eurephia_nullsafe.h>
00043 #include <certinfo.h>
00044 
00045 #include "get_console_input.h"
00046 #define _PARSE_CERTFICIATE_FILES_C
00047 #include "parse_certificate_files.h"
00048 
00049 
00059 char *ExtractCertInfo(const char *module, X509 *cert, const char *fieldname) {
00060         unsigned char *buf = (unsigned char *)1;  // Needs to be 1 to avoid OpenSSL 0.9.6b bug
00061         char resbuf[2050];
00062         X509_NAME *name = NULL;
00063         X509_NAME_ENTRY *namentry = NULL;
00064         ASN1_STRING *asn1 = NULL;
00065         int nid, tmp = -1, pos = -1;
00066 
00067         //
00068         // Extract subject information
00069         //
00070 
00071         memset(resbuf, 0, 2050);
00072 
00073         nid = OBJ_txt2nid(fieldname);
00074         name = X509_get_subject_name(cert);
00075 
00076         do {
00077                 pos = tmp;
00078                 tmp = X509_NAME_get_index_by_NID(name, nid, pos);
00079         } while ( tmp > -1 );
00080 
00081         if( pos == -1 ) {
00082                 fprintf(stderr, "%s: Field '%s' not found\n", module, fieldname);
00083                 return 0;
00084         }
00085 
00086         if( !(namentry = X509_NAME_get_entry(name, pos)) ) {
00087                 fprintf(stderr, "%s: Failed to extract name entry from field '%s'\n", module, fieldname);
00088                 return 0;
00089         }
00090 
00091         if( !(asn1 = X509_NAME_ENTRY_get_data(namentry)) ) {
00092                 fprintf(stderr, "%s: Failed to extract data from name entry field '%s'\n", module, fieldname);
00093                 return 0;
00094         }
00095 
00096         if( ASN1_STRING_to_UTF8(&buf, asn1) <= 0 ) {
00097                 fprintf(stderr, "%s: Failed to convert ASN1 string to UTF-8 for '%s'\n", module, fieldname);
00098                 return 0;
00099         }
00100 
00101         snprintf(resbuf, 2048, "%s%c", buf, '\0');
00102         OPENSSL_free(buf);
00103 
00104         return strdup_nullsafe(resbuf);
00105 }
00106 
00107 
00118 certinfo *_Cert_ParseFile(const char *module, const char *certfile, int certfile_format) {
00119         BIO *bio_err = NULL;
00120         PKCS12 *p12 = NULL;
00121         EVP_PKEY *pkey = NULL;
00122         X509 *cert = NULL;
00123         FILE *fp;
00124         certinfo *ret = NULL;
00125 
00126         /* Needed to convert X509 digest into hex string */
00127         unsigned char md_sha1[EVP_MAX_MD_SIZE];
00128         unsigned int mdlen;
00129 
00130         if( !bio_err ) {
00131                 SSL_library_init();
00132                 SSL_load_error_strings();
00133                 bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
00134         }
00135 
00136         // Open file - according to defined format
00137         switch( certfile_format ) {
00138         case CERTFILE_PEM: // PEM/DER format
00139                 fp = fopen(certfile, "r");
00140                 if( !(cert = PEM_read_X509(fp, NULL, NULL, NULL)) ) {
00141                         fprintf(stderr, "%s: Failed to open certificate file\n", module);
00142                         return NULL;
00143                 }
00144                 fclose(fp);
00145                 break;
00146 
00147         case CERTFILE_PKCS12: // PKCS#12 format
00148                 fp = fopen(certfile, "r");
00149                 p12 = d2i_PKCS12_fp(fp, NULL);
00150                 fclose(fp);
00151                 if( p12 == NULL ) {
00152                         fprintf(stderr, "%s: Could not open PKCS#12 file\n", module);
00153                         return NULL;
00154                 }
00155                 OpenSSL_add_all_ciphers();
00156 
00157                 // First, try without password
00158                 if( !PKCS12_parse(p12, "", &pkey, &cert, NULL) ) {
00159                         char pwd[130];
00160 
00161                         // If empty password failed, get password and try again
00162                         memset(&pwd, 0, 130);
00163                         if( get_console_input(pwd, 128, "PKCS12 password:", 1) < 0 ) {
00164                                 fprintf(stderr, "Could not retrieve password\n");
00165                         }
00166                         if( !PKCS12_parse(p12, pwd, &pkey, &cert, NULL) ) {
00167                                 PKCS12_free(p12); p12 = NULL;
00168                                 fprintf(stderr,
00169                                         "%s: Could not open PKCS#12 file - wrong password\n", module);
00170                                 fprintf(stderr,
00171                                         "%s: %s\n", module, ERR_error_string(ERR_get_error(), NULL));
00172                                 BIO_free(bio_err);
00173                                 return NULL;
00174                         }
00175                 }
00176                 EVP_PKEY_free(pkey); pkey = NULL;
00177                 PKCS12_free(p12); p12 = NULL;
00178                 break;
00179 
00180         default: // Unknown
00181                 fprintf(stderr, "%s: Unknown certificate file format\n", module);
00182                 return NULL;
00183         }
00184 
00185         ret = (certinfo *) malloc_nullsafe(NULL, sizeof(certinfo)+2);
00186         assert( ret != NULL );
00187 
00188         ret->digest = (char *) malloc_nullsafe(NULL, 66);
00189         assert(ret != NULL);
00190 
00191 
00192         // extract SHA1 digest from certificate
00193         if (X509_digest(cert, EVP_sha1(), md_sha1, &mdlen) && mdlen > 0) {
00194                 static const char hexcodes[] = "0123456789ABCDEF";
00195                 int j;
00196 
00197                 for (j = 0; j < (int) mdlen; j++) {
00198                         ret->digest[j * 3] = hexcodes[(md_sha1[j] & 0xf0) >> 4U];
00199                         ret->digest[(j * 3) + 1] = hexcodes[(md_sha1[j] & 0x0f)];
00200                         if (j + 1 != (int) mdlen) {
00201                                 ret->digest[(j * 3) + 2] = ':';
00202                         } else {
00203                                 ret->digest[(j * 3) + 2] = '\0';
00204                         }
00205                 }
00206         }
00207 
00208         // Extract the subject information we want
00209         ret->common_name = ExtractCertInfo(module, cert, "CN");
00210         ret->org         = ExtractCertInfo(module, cert, "O");
00211         ret->email       = ExtractCertInfo(module, cert, "emailAddress");
00212 
00213         X509_free(cert);
00214         BIO_free(bio_err);
00215 
00216         return ret;
00217 }
00218 #endif
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines