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     char *digest_algorithm;
00042     ssize_t pubkey_digest_length;
00043     unsigned char pubkey_digest[SHA256_DIGEST_LENGTH];
00044 };
00045 
00046 struct ccn_keystore *
00047 ccn_keystore_create(void)
00048 {
00049     struct ccn_keystore *res = calloc(1, sizeof(*res));
00050     return (res);
00051 }
00052 
00053 void
00054 ccn_keystore_destroy(struct ccn_keystore **p)
00055 {
00056     if (*p != NULL) {
00057         if ((*p)->private_key != NULL)
00058             EVP_PKEY_free((*p)->private_key);
00059         if ((*p)->public_key != NULL)
00060             EVP_PKEY_free((*p)->public_key);
00061         if ((*p)->certificate != NULL)
00062             X509_free((*p)->certificate);
00063         if ((*p)->digest_algorithm != NULL)
00064             free((*p)->digest_algorithm);
00065         free(*p);
00066         *p = NULL;
00067     }
00068 }
00069 
00070 int
00071 ccn_keystore_init(struct ccn_keystore *p, char *filename, char *password)
00072 {
00073     FILE *fp;
00074     PKCS12 *keystore;
00075     ASN1_OBJECT *digest_obj;
00076     int digest_size;
00077     int res;
00078 
00079     OpenSSL_add_all_algorithms();
00080     fp = fopen(filename, "rb");
00081     if (fp == NULL)
00082         return (-1);
00083 
00084     keystore = d2i_PKCS12_fp(fp, NULL);
00085     fclose(fp);
00086     if (keystore == NULL)
00087         return (-1);
00088 
00089     res = PKCS12_parse(keystore, password, &(p->private_key), &(p->certificate), NULL);
00090     PKCS12_free(keystore);
00091     if (res == 0) {
00092         return (-1);
00093     }
00094     p->public_key = X509_get_pubkey(p->certificate);
00095     /* cache the public key digest to avoid work later */
00096     if (1 != ASN1_item_digest(ASN1_ITEM_rptr(X509_PUBKEY), EVP_sha256(),
00097                               X509_get_X509_PUBKEY(p->certificate),
00098                               p->pubkey_digest, NULL)) return (-1);
00099     p->pubkey_digest_length = SHA256_DIGEST_LENGTH;
00100 
00101     /* check if the key-pair requires a particular digest algorithm.
00102      * ECDSA keys from 160 through 383 bits are OK with SHA-256 (n.b. RFC5480)
00103      */
00104     
00105     switch (EVP_PKEY_type(p->private_key->type)) {
00106         case EVP_PKEY_DSA:
00107             digest_obj = OBJ_nid2obj(NID_sha1);
00108             break;
00109         default:
00110             digest_obj = NULL;
00111     }
00112     if (digest_obj) {
00113         digest_size = 1 + OBJ_obj2txt(NULL, 0, digest_obj, 1);
00114         p->digest_algorithm = calloc(1, digest_size);
00115         OBJ_obj2txt(p->digest_algorithm, digest_size, digest_obj, 1);        
00116     } else {
00117         p->digest_algorithm = NULL;
00118     }
00119     
00120     p->initialized = 1;
00121     return (0);
00122 }
00123 
00124 const struct ccn_pkey *
00125 ccn_keystore_private_key(struct ccn_keystore *p)
00126 {
00127     if (0 == p->initialized)
00128         return (NULL);
00129 
00130     return ((const struct ccn_pkey *)(p->private_key));
00131 }
00132 
00133 const struct ccn_pkey *
00134 ccn_keystore_public_key(struct ccn_keystore *p)
00135 {
00136     if (0 == p->initialized)
00137         return (NULL);
00138 
00139     return ((const struct ccn_pkey *)(p->public_key));
00140 }
00141 
00142 const char *
00143 ccn_keystore_digest_algorithm(struct ccn_keystore *p)
00144 {
00145     if (0 == p->initialized)
00146         return (NULL);
00147     return (p->digest_algorithm);
00148 }
00149 
00150 ssize_t
00151 ccn_keystore_public_key_digest_length(struct ccn_keystore *p)
00152 {
00153     return ((0 == p->initialized) ? -1 : p->pubkey_digest_length);
00154 }
00155 
00156 const unsigned char *
00157 ccn_keystore_public_key_digest(struct ccn_keystore *p)
00158 {
00159     if (0 == p->initialized)
00160         return (NULL);
00161     return (p->pubkey_digest);
00162 }
00163 
00164 const struct ccn_certificate *
00165 ccn_keystore_certificate(struct ccn_keystore *p)
00166 {
00167     if (0 == p->initialized)
00168         return (NULL);
00169 
00170     return ((const void *)(p->certificate));
00171 }
00172 
00173 static int
00174 add_cert_extension_with_context(X509 *cert, int nid, char *value)
00175 {
00176     X509_EXTENSION *extension;
00177     X509V3_CTX context;
00178     
00179     X509V3_set_ctx_nodb(&context);
00180     X509V3_set_ctx(&context, cert, cert, NULL, NULL, 0);
00181     extension = X509V3_EXT_conf_nid(NULL, &context, nid, value);
00182     if (extension == NULL)
00183         return(0);
00184     X509_add_ext(cert, extension, -1);
00185     X509_EXTENSION_free(extension);
00186     return(1);
00187 }
00188 
00189 static int
00190 add_cert_extension(X509 *cert, int nid, char *value)
00191 {
00192     X509_EXTENSION *extension;
00193     extension = X509V3_EXT_conf_nid(NULL, NULL, nid, value);
00194     if (extension == NULL)
00195         return(0);
00196     X509_add_ext(cert, extension, -1);
00197     X509_EXTENSION_free(extension);
00198     return(1);
00199 }
00200 /**
00201  * Create a PKCS12 keystore file
00202  * @param filename  the name of the keystore file to be created.
00203  * @param password  the import/export password for the keystore.
00204  * @param subject   the subject (and issuer) name in the certificate.
00205  * @param keylength the number of bits in the RSA key to be generated.
00206  *                  A value <= 0 will result in the default (1024) being used.
00207  * @param validity_days the number of days the certificate in the keystore will
00208  *                  be valid.  A value <= 0 will result in the default (30) being used.
00209  * @returns 0 on success, -1 on failure
00210  */
00211 int
00212 ccn_keystore_file_init(char *filename, char *password,
00213                        char *subject, int keylength, int validity_days)
00214 {
00215         RSA *rsa = RSA_new();
00216     BIGNUM *pub_exp = BN_new();
00217     EVP_PKEY *pkey = EVP_PKEY_new();
00218     X509 *cert = X509_new();
00219     X509_NAME *name = NULL;
00220     PKCS12 *pkcs12 = NULL;
00221     unsigned char spkid[SHA256_DIGEST_LENGTH];
00222     char spkid_hex[1 + 2 * SHA256_DIGEST_LENGTH];
00223     unsigned long serial = 0;
00224     unsigned char serial_bytes[sizeof(serial)];
00225     FILE *fp = NULL;
00226     int fd = -1;
00227     int res;
00228     int i;
00229     int ans = -1;
00230     
00231     // Check whether initial allocations succeeded.
00232     if (rsa == NULL || pub_exp == NULL || pkey == NULL || cert == NULL)
00233         goto Bail;
00234     
00235     // Set up default values for keylength and expiration.
00236     if (keylength <= 0)
00237         keylength = 1024;
00238     if (validity_days <= 0)
00239         validity_days = 30;
00240     
00241     OpenSSL_add_all_algorithms();
00242     
00243     BN_set_word(pub_exp, RSA_F4);
00244     res = 1;
00245     res &= RSA_generate_key_ex(rsa, keylength, pub_exp, NULL);
00246     res &= EVP_PKEY_set1_RSA(pkey, rsa);
00247     res &= X509_set_version(cert, 2);       // 2 => X509v3
00248         if (res == 0)
00249         goto Bail;
00250     
00251     // Construct random positive serial number.
00252     RAND_bytes(serial_bytes, sizeof(serial_bytes));
00253     serial_bytes[0] &= 0x7F;
00254     serial = 0;
00255     for (i=0; i < sizeof(serial_bytes); i++) {
00256         serial = (256 * serial) + serial_bytes[i];
00257     }
00258         ASN1_INTEGER_set(X509_get_serialNumber(cert), serial);
00259     
00260     // Set the validity from now for the specified number of days.
00261     X509_gmtime_adj(X509_get_notBefore(cert), (long)0);
00262     X509_gmtime_adj(X509_get_notAfter(cert), (long)(60 * 60 * 24 * validity_days));
00263     X509_set_pubkey(cert, pkey);
00264     
00265     // Set up the simple subject name and issuer name for the certificate.
00266     name = X509_get_subject_name(cert);
00267     if (name == NULL)
00268         goto Bail;
00269     res = X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char *)subject, -1, -1, 0);
00270         res &= X509_set_issuer_name(cert, name);
00271     
00272     // Add the necessary extensions.
00273     res &= add_cert_extension(cert, NID_basic_constraints, "critical,CA:FALSE");
00274     res &= add_cert_extension(cert, NID_key_usage, "digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement");
00275     res &= add_cert_extension(cert, NID_ext_key_usage, "clientAuth");
00276     
00277     if (res == 0)
00278         goto Bail;
00279     
00280     /* Generate a KeyID which is the SHA256 digest of the DER encoding
00281          * of a SubjectPublicKeyInfo.  Note that this is slightly uncommon,
00282          * but it is more general and complete than digesting the BIT STRING
00283          * component of the SubjectPublicKeyInfo itself (and no standard dictates
00284          * how you must generate a key ID).  This code must produce the same result
00285      * as the Java version applied to the same SubjectPublicKeyInfo.
00286      */
00287     
00288     res = ASN1_item_digest(ASN1_ITEM_rptr(X509_PUBKEY), EVP_sha256(),
00289                            X509_get_X509_PUBKEY(cert),
00290                            spkid, NULL);
00291     
00292     for (i = 0; i < 32; i++) snprintf(&spkid_hex[2 * i], 3, "%02X", (unsigned)spkid[i]);
00293     res &= add_cert_extension(cert, NID_subject_key_identifier, spkid_hex);
00294     res &= add_cert_extension_with_context(cert, NID_authority_key_identifier, "keyid:always");
00295     if (res == 0)
00296         goto Bail;
00297     
00298     // The certificate is complete, sign it.
00299     res = X509_sign(cert, pkey, EVP_sha1());
00300     if (res == 0)
00301         goto Bail;
00302 
00303     // construct the full PKCS12 keystore to hold the certificate and private key
00304     pkcs12 = PKCS12_create(password,  "ccnxuser", pkey, cert, NULL, 0, 0,
00305                            0 /*default iter*/, PKCS12_DEFAULT_ITER /*mac_iter*/, 0);
00306     if (pkcs12 == NULL)
00307         goto Bail;
00308     
00309     fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0600);
00310     if (fd == -1)
00311         goto Bail;
00312     fp = fdopen(fd, "wb");
00313     if (fp == NULL)
00314         goto Bail;
00315     i2d_PKCS12_fp(fp, pkcs12);
00316     fclose(fp);
00317     fd = -1;
00318     
00319     ans = 0;
00320     
00321     // For debugging, the following may be helpful:
00322     // RSA_print_fp(stderr, pkey->pkey.rsa, 0); */
00323     // X509_print_fp(stderr, cert);
00324         // PEM_write_PrivateKey(stderr, pkey, NULL, NULL, 0, NULL, NULL); */
00325         // PEM_write_X509(stderr, cert);
00326     
00327     
00328 Bail:
00329     if (fd != -1)
00330         close(fd);
00331     if (pkey != NULL) {
00332         EVP_PKEY_free(pkey);
00333         pkey = NULL;
00334     }
00335     if (rsa != NULL) {
00336         RSA_free(rsa);
00337         rsa = NULL;
00338     }
00339     if (pub_exp != NULL){
00340         BN_free(pub_exp);
00341         pub_exp = NULL;
00342     }
00343     if (cert != NULL) {
00344         X509_free(cert);
00345         cert = NULL;
00346     }
00347     if (pkcs12 != NULL) {
00348         PKCS12_free(pkcs12);
00349         pkcs12 = NULL;
00350     }
00351     return (ans);
00352 }
Generated on Tue Aug 21 14:54:18 2012 for Content-Centric Networking in C by  doxygen 1.6.3