ccn_keystore.c

Go to the documentation of this file.
00001 /**
00002  * @file ccn_keystore.c
00003  * @brief Support for keystore access.
00004  * 
00005  * Part of the CCNx C Library.
00006  *
00007  * Copyright (C) 2009 Palo Alto Research Center, Inc.
00008  *
00009  * This library is free software; you can redistribute it and/or modify it
00010  * under the terms of the GNU Lesser General Public License version 2.1
00011  * as published by the Free Software Foundation.
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00015  * Lesser General Public License for more details. You should have received
00016  * a copy of the GNU Lesser General Public License along with this library;
00017  * if not, write to the Free Software Foundation, Inc., 51 Franklin Street,
00018  * Fifth Floor, Boston, MA 02110-1301 USA.
00019  */
00020 #include <stdio.h>
00021 #include <stdlib.h>
00022 #include <unistd.h>
00023 #include <string.h>
00024 #include <ctype.h>
00025 #include <fcntl.h>
00026 #include <openssl/bn.h>
00027 #include <openssl/rsa.h>
00028 #include <openssl/evp.h>
00029 #include <openssl/x509v3.h>
00030 #include <openssl/pkcs12.h>
00031 #include <openssl/sha.h>
00032 #include <openssl/rand.h>
00033 
00034 #include <ccn/keystore.h>
00035 
00036 struct ccn_keystore {
00037     int initialized;
00038     EVP_PKEY *private_key;
00039     EVP_PKEY *public_key;
00040     X509 *certificate;
00041     ssize_t pubkey_digest_length;
00042     unsigned char pubkey_digest[SHA256_DIGEST_LENGTH];
00043 };
00044 
00045 struct ccn_keystore *
00046 ccn_keystore_create(void)
00047 {
00048     struct ccn_keystore *res = calloc(1, sizeof(*res));
00049     return (res);
00050 }
00051 
00052 void
00053 ccn_keystore_destroy(struct ccn_keystore **p)
00054 {
00055     if (*p != NULL) {
00056         if ((*p)->private_key != NULL)
00057             EVP_PKEY_free((*p)->private_key);
00058         if ((*p)->public_key != NULL)
00059             EVP_PKEY_free((*p)->public_key);
00060         if ((*p)->certificate != NULL)
00061             X509_free((*p)->certificate);
00062         free(*p);
00063         *p = NULL;
00064     }
00065 }
00066 
00067 int
00068 ccn_keystore_init(struct ccn_keystore *p, char *filename, char *password)
00069 {
00070     FILE *fp;
00071     PKCS12 *keystore;
00072     int res;
00073 
00074     OpenSSL_add_all_algorithms();
00075     fp = fopen(filename, "rb");
00076     if (fp == NULL)
00077         return (-1);
00078 
00079     keystore = d2i_PKCS12_fp(fp, NULL);
00080     fclose(fp);
00081     if (keystore == NULL)
00082         return (-1);
00083 
00084     res = PKCS12_parse(keystore, password, &(p->private_key), &(p->certificate), NULL);
00085     PKCS12_free(keystore);
00086     if (res == 0) {
00087         return (-1);
00088     }
00089     p->public_key = X509_get_pubkey(p->certificate);
00090     /* cache the public key digest to avoid work later */
00091     if (1 != ASN1_item_digest(ASN1_ITEM_rptr(X509_PUBKEY), EVP_sha256(),
00092                               X509_get_X509_PUBKEY(p->certificate),
00093                               p->pubkey_digest, NULL)) return (-1);
00094     p->pubkey_digest_length = SHA256_DIGEST_LENGTH;
00095     p->initialized = 1;
00096     return (0);
00097 }
00098 
00099 const struct ccn_pkey *
00100 ccn_keystore_private_key(struct ccn_keystore *p)
00101 {
00102     if (0 == p->initialized)
00103         return (NULL);
00104 
00105     return ((const struct ccn_pkey *)(p->private_key));
00106 }
00107 
00108 const struct ccn_pkey *
00109 ccn_keystore_public_key(struct ccn_keystore *p)
00110 {
00111     if (0 == p->initialized)
00112         return (NULL);
00113 
00114     return ((const struct ccn_pkey *)(p->public_key));
00115 }
00116 
00117 ssize_t
00118 ccn_keystore_public_key_digest_length(struct ccn_keystore *p)
00119 {
00120     return ((0 == p->initialized) ? -1 : p->pubkey_digest_length);
00121 }
00122 
00123 const unsigned char *
00124 ccn_keystore_public_key_digest(struct ccn_keystore *p)
00125 {
00126     if (0 == p->initialized)
00127         return (NULL);
00128     return (p->pubkey_digest);
00129 }
00130 
00131 const struct ccn_certificate *
00132 ccn_keystore_certificate(struct ccn_keystore *p)
00133 {
00134     if (0 == p->initialized)
00135         return (NULL);
00136 
00137     return ((const void *)(p->certificate));
00138 }
00139 
00140 static int
00141 add_cert_extension_with_context(X509 *cert, int nid, char *value)
00142 {
00143     X509_EXTENSION *extension;
00144     X509V3_CTX context;
00145     
00146     X509V3_set_ctx_nodb(&context);
00147     X509V3_set_ctx(&context, cert, cert, NULL, NULL, 0);
00148     extension = X509V3_EXT_conf_nid(NULL, &context, nid, value);
00149     if (extension == NULL)
00150         return(0);
00151     X509_add_ext(cert, extension, -1);
00152     X509_EXTENSION_free(extension);
00153     return(1);
00154 }
00155 
00156 static int
00157 add_cert_extension(X509 *cert, int nid, char *value)
00158 {
00159     X509_EXTENSION *extension;
00160     extension = X509V3_EXT_conf_nid(NULL, NULL, nid, value);
00161     if (extension == NULL)
00162         return(0);
00163     X509_add_ext(cert, extension, -1);
00164     X509_EXTENSION_free(extension);
00165     return(1);
00166 }
00167 /**
00168  * Create a PKCS12 keystore file
00169  * @param filename  the name of the keystore file to be created.
00170  * @param password  the import/export password for the keystore.
00171  * @param subject   the subject (and issuer) name in the certificate.
00172  * @param keylength the number of bits in the RSA key to be generated.
00173  *                  A value <= 0 will result in the default (1024) being used.
00174  * @param validity_days the number of days the certificate in the keystore will
00175  *                  be valid.  A value <= 0 will result in the default (30) being used.
00176  * @returns 0 on success, -1 on failure
00177  */
00178 int
00179 ccn_keystore_file_init(char *filename, char *password,
00180                        char *subject, int keylength, int validity_days)
00181 {
00182         RSA *rsa = RSA_new();
00183     BIGNUM *pub_exp = BN_new();
00184     EVP_PKEY *pkey = EVP_PKEY_new();
00185     X509 *cert = X509_new();
00186     X509_NAME *name = NULL;
00187     PKCS12 *pkcs12 = NULL;
00188     unsigned char spkid[SHA256_DIGEST_LENGTH];
00189     char spkid_hex[1 + 2 * SHA256_DIGEST_LENGTH];
00190     unsigned long serial = 0;
00191     unsigned char serial_bytes[sizeof(serial)];
00192     FILE *fp = NULL;
00193     int fd = -1;
00194     int res;
00195     int i;
00196     int ans = -1;
00197     
00198     // Check whether initial allocations succeeded.
00199     if (rsa == NULL || pub_exp == NULL || pkey == NULL || cert == NULL)
00200         goto Bail;
00201     
00202     // Set up default values for keylength and expiration.
00203     if (keylength <= 0)
00204         keylength = 1024;
00205     if (validity_days <= 0)
00206         validity_days = 30;
00207     
00208     OpenSSL_add_all_algorithms();
00209     
00210     BN_set_word(pub_exp, RSA_F4);
00211     res = 1;
00212     res &= RSA_generate_key_ex(rsa, keylength, pub_exp, NULL);
00213     res &= EVP_PKEY_set1_RSA(pkey, rsa);
00214     res &= X509_set_version(cert, 2);       // 2 => X509v3
00215         if (res == 0)
00216         goto Bail;
00217     
00218     // Construct random positive serial number.
00219     RAND_bytes(serial_bytes, sizeof(serial_bytes));
00220     serial_bytes[0] &= 0x7F;
00221     serial = 0;
00222     for (i=0; i < sizeof(serial_bytes); i++) {
00223         serial = (256 * serial) + serial_bytes[i];
00224     }
00225         ASN1_INTEGER_set(X509_get_serialNumber(cert), serial);
00226     
00227     // Set the validity from now for the specified number of days.
00228     X509_gmtime_adj(X509_get_notBefore(cert), (long)0);
00229     X509_gmtime_adj(X509_get_notAfter(cert), (long)(60 * 60 * 24 * validity_days));
00230     X509_set_pubkey(cert, pkey);
00231     
00232     // Set up the simple subject name and issuer name for the certificate.
00233     name = X509_get_subject_name(cert);
00234     if (name == NULL)
00235         goto Bail;
00236     res = X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char *)subject, -1, -1, 0);
00237         res &= X509_set_issuer_name(cert, name);
00238     
00239     // Add the necessary extensions.
00240     res &= add_cert_extension(cert, NID_basic_constraints, "critical,CA:FALSE");
00241     res &= add_cert_extension(cert, NID_key_usage, "digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement");
00242     res &= add_cert_extension(cert, NID_ext_key_usage, "clientAuth");
00243     
00244     if (res == 0)
00245         goto Bail;
00246     
00247     /* Generate a KeyID which is the SHA256 digest of the DER encoding
00248          * of a SubjectPublicKeyInfo.  Note that this is slightly uncommon,
00249          * but it is more general and complete than digesting the BIT STRING
00250          * component of the SubjectPublicKeyInfo itself (and no standard dictates
00251          * how you must generate a key ID).  This code must produce the same result
00252      * as the Java version applied to the same SubjectPublicKeyInfo.
00253      */
00254     
00255     res = ASN1_item_digest(ASN1_ITEM_rptr(X509_PUBKEY), EVP_sha256(),
00256                            X509_get_X509_PUBKEY(cert),
00257                            spkid, NULL);
00258     
00259     for (i = 0; i < 32; i++) snprintf(&spkid_hex[2 * i], 3, "%02X", (unsigned)spkid[i]);
00260     res &= add_cert_extension(cert, NID_subject_key_identifier, spkid_hex);
00261     res &= add_cert_extension_with_context(cert, NID_authority_key_identifier, "keyid:always");
00262     if (res == 0)
00263         goto Bail;
00264     
00265     // The certificate is complete, sign it.
00266     res = X509_sign(cert, pkey, EVP_sha1());
00267     if (res == 0)
00268         goto Bail;
00269 
00270     // construct the full PKCS12 keystore to hold the certificate and private key
00271     pkcs12 = PKCS12_create(password,  "ccnxuser", pkey, cert, NULL, 0, 0,
00272                            0 /*default iter*/, PKCS12_DEFAULT_ITER /*mac_iter*/, 0);
00273     if (pkcs12 == NULL)
00274         goto Bail;
00275     
00276     fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0600);
00277     if (fd == -1)
00278         goto Bail;
00279     fp = fdopen(fd, "wb");
00280     if (fp == NULL)
00281         goto Bail;
00282     i2d_PKCS12_fp(fp, pkcs12);
00283     fclose(fp);
00284     fd = -1;
00285     
00286     ans = 0;
00287     
00288     // For debugging, the following may be helpful:
00289     // RSA_print_fp(stderr, pkey->pkey.rsa, 0); */
00290     // X509_print_fp(stderr, cert);
00291         // PEM_write_PrivateKey(stderr, pkey, NULL, NULL, 0, NULL, NULL); */
00292         // PEM_write_X509(stderr, cert);
00293     
00294     
00295 Bail:
00296     if (fd != -1)
00297         close(fd);
00298     if (pkey != NULL) {
00299         EVP_PKEY_free(pkey);
00300         pkey = NULL;
00301     }
00302     if (rsa != NULL) {
00303         RSA_free(rsa);
00304         rsa = NULL;
00305     }
00306     if (pub_exp != NULL){
00307         BN_free(pub_exp);
00308         pub_exp = NULL;
00309     }
00310     if (cert != NULL) {
00311         X509_free(cert);
00312         cert = NULL;
00313     }
00314     if (pkcs12 != NULL) {
00315         PKCS12_free(pkcs12);
00316         pkcs12 = NULL;
00317     }
00318     return (ans);
00319 }

Generated on Thu Feb 16 00:44:00 2012 for Content-Centric Networking in C by  doxygen 1.5.6