ccn_signing.c

Go to the documentation of this file.
00001 /**
00002  * @file ccn_signing.c
00003  * @brief Support for signing.
00004  * 
00005  * Part of the CCNx C Library.
00006  *
00007  * Copyright (C) 2009-2010 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 <stddef.h>
00021 #include <stdlib.h>
00022 #include <string.h>
00023 #include <openssl/evp.h>
00024 #include <openssl/rand.h>
00025 #include <openssl/x509.h>
00026 #include <ccn/merklepathasn1.h>
00027 #include <ccn/ccn.h>
00028 #include <ccn/signing.h>
00029 #include <ccn/random.h>
00030 
00031 struct ccn_sigc {
00032     EVP_MD_CTX context;
00033     const EVP_MD *digest;
00034 };
00035 
00036 struct ccn_sigc *
00037 ccn_sigc_create(void)
00038 {
00039     return (calloc(1, sizeof(struct ccn_sigc)));
00040 }
00041 
00042 void
00043 ccn_sigc_destroy(struct ccn_sigc **ctx)
00044 {
00045     if (*ctx) {
00046         // XXX - is it OK to call cleanup unconditionally?
00047         EVP_MD_CTX_cleanup(&(*ctx)->context);
00048         free(*ctx);
00049         *ctx = NULL;
00050     }
00051 }
00052 
00053 int
00054 ccn_sigc_init(struct ccn_sigc *ctx, const char *digest)
00055 {
00056     EVP_MD_CTX_init(&ctx->context);
00057     if (digest == NULL) {
00058         ctx->digest = EVP_sha256();
00059     }
00060     else {
00061         /* XXX - figure out what algorithm the OID represents */
00062         fprintf(stderr, "not a DigestAlgorithm I understand right now\n");
00063         return (-1);
00064     }
00065 
00066     if (0 == EVP_SignInit_ex(&ctx->context, ctx->digest, NULL))
00067         return (-1);
00068     return (0);
00069 }
00070 
00071 int
00072 ccn_sigc_update(struct ccn_sigc *ctx, const void *data, size_t size)
00073 {
00074     if (0 == EVP_SignUpdate(&ctx->context, (unsigned char *)data, size))
00075         return (-1);
00076     return (0);
00077 }
00078 
00079 int
00080 ccn_sigc_final(struct ccn_sigc *ctx, struct ccn_signature *signature, size_t *size, const struct ccn_pkey *priv_key)
00081 {
00082     unsigned int sig_size;
00083 
00084     if (0 == EVP_SignFinal(&ctx->context, (unsigned char *)signature, &sig_size, (EVP_PKEY *)priv_key))
00085         return (-1);
00086     *size = sig_size;
00087     return (0);
00088 }
00089 
00090 size_t
00091 ccn_sigc_signature_max_size(struct ccn_sigc *ctx, const struct ccn_pkey *priv_key)
00092 {
00093     return (EVP_PKEY_size((EVP_PKEY *)priv_key));
00094 }
00095 
00096 #define is_left(x) (0 == (x & 1))
00097 #define node_lr(x) (x & 1)
00098 #define sibling_of(x) (x ^ 1)
00099 #define parent_of(x) (x >> 1)
00100 
00101 int ccn_merkle_root_hash(const unsigned char *msg, size_t size,
00102                          const struct ccn_parsed_ContentObject *co,
00103                          const EVP_MD *digest_type,
00104                          MP_info *merkle_path_info,
00105                          unsigned char *result, int result_size)
00106 {
00107     int node = ASN1_INTEGER_get(merkle_path_info->node);
00108     EVP_MD_CTX digest_context;
00109     EVP_MD_CTX *digest_contextp = &digest_context;
00110     size_t data_size;
00111     unsigned char *input_hash[2] = {NULL, NULL};
00112     //int hash_count = sk_ASN1_OCTET_STRING_num(merkle_path_info->hashes);
00113     int hash_index = sk_ASN1_OCTET_STRING_num(merkle_path_info->hashes) - 1;
00114     //ASN1_OCTET_STRING *sibling_hash;
00115     int res;
00116     
00117     if (result_size != EVP_MD_size(digest_type))
00118         return -1;
00119 
00120     /*
00121      * This is the calculation for the node we're starting from
00122      *
00123      * The digest type for the leaf node we'll take from the MHT OID
00124      * We can assume that, since we're using the same digest function, the
00125      * result size will always be the same.
00126      */
00127 
00128     EVP_MD_CTX_init(digest_contextp);
00129     EVP_DigestInit_ex(digest_contextp, digest_type, NULL);
00130     data_size = co->offset[CCN_PCO_E_Content] - co->offset[CCN_PCO_B_Name];
00131     res = EVP_DigestUpdate(digest_contextp, msg + co->offset[CCN_PCO_B_Name], data_size);
00132     res &= EVP_DigestFinal_ex(digest_contextp, result, NULL);
00133     if (res != 1)
00134         return(-1);
00135     /* input_hash[0, 1] = address of hash for (left,right) node of parent
00136      */
00137     while (node != 1) {
00138         input_hash[node & 1] = result;
00139         input_hash[(node & 1) ^ 1] = sk_ASN1_OCTET_STRING_value(merkle_path_info->hashes, hash_index)->data;
00140         if (sk_ASN1_OCTET_STRING_value(merkle_path_info->hashes, hash_index)->length != result_size)
00141             return (-1);
00142         hash_index -= 1;
00143 #ifdef DEBUG
00144         fprintf(stderr, "node[%d].lefthash = ", parent_of(node));
00145         for (int x = 0; x < result_size; x++) {
00146             fprintf(stderr, "%02x", input_hash[0][x]);
00147         }
00148         fprintf(stderr, "\n");
00149    
00150         fprintf(stderr, "node[%d].righthash = ", parent_of(node));
00151         for (int x = 0; x < result_size; x++) {
00152             fprintf(stderr, "%02x", input_hash[1][x]);
00153         }
00154         fprintf(stderr, "\n");
00155 #endif
00156         EVP_MD_CTX_init(digest_contextp);
00157         res = EVP_DigestInit_ex(digest_contextp, digest_type, NULL);
00158         res &= EVP_DigestUpdate(digest_contextp, input_hash[0], result_size);
00159         res &= EVP_DigestUpdate(digest_contextp, input_hash[1], result_size);
00160         res &= EVP_DigestFinal_ex(digest_contextp, result, NULL);
00161         if (res != 1)
00162             return(-1);
00163         node = parent_of(node);
00164    
00165 #ifdef DEBUG
00166         fprintf(stderr, "yielding node[%d] hash = ", node);
00167         for (int x = 0; x < result_size; x++) {
00168             fprintf(stderr, "%02x", result[x]);
00169         }
00170         fprintf(stderr, "\n");
00171 #endif
00172     }
00173     return (0);
00174 }
00175 
00176 int ccn_verify_signature(const unsigned char *msg,
00177                      size_t size,
00178                      const struct ccn_parsed_ContentObject *co,
00179                      const struct ccn_pkey *verification_pubkey)
00180 {
00181     EVP_MD_CTX verc;
00182     EVP_MD_CTX *ver_ctx = &verc;
00183     X509_SIG *digest_info = NULL;
00184     MP_info *merkle_path_info = NULL;
00185     unsigned char *root_hash;
00186     size_t root_hash_size;
00187 
00188     int res;
00189 
00190     const EVP_MD *digest;
00191     const EVP_MD *merkle_path_digest;
00192 
00193     const unsigned char *signature_bits = NULL;
00194     size_t signature_bits_size = 0;
00195     const unsigned char *witness = NULL;
00196     size_t witness_size = 0;
00197     EVP_PKEY *pkey = (EVP_PKEY *)verification_pubkey;
00198 #ifdef DEBUG
00199     int x, h;
00200 #endif
00201 
00202     res = ccn_ref_tagged_BLOB(CCN_DTAG_SignatureBits, msg,
00203                               co->offset[CCN_PCO_B_SignatureBits],
00204                               co->offset[CCN_PCO_E_SignatureBits],
00205                               &signature_bits,
00206                               &signature_bits_size);
00207     if (res < 0)
00208         return (-1);
00209 
00210     if (co->offset[CCN_PCO_B_DigestAlgorithm] == co->offset[CCN_PCO_E_DigestAlgorithm]) {
00211         digest = EVP_sha256();
00212     }
00213     else {
00214         /* XXX - figure out what algorithm the OID represents */
00215         fprintf(stderr, "not a DigestAlgorithm I understand right now\n");
00216         return (-1);
00217     }
00218 
00219     EVP_MD_CTX_init(ver_ctx);
00220     res = EVP_VerifyInit_ex(ver_ctx, digest, NULL);
00221     if (!res)
00222         return (-1);
00223 
00224     if (co->offset[CCN_PCO_B_Witness] != co->offset[CCN_PCO_E_Witness]) {
00225         /* The witness is a DigestInfo, where the octet-string therein encapsulates
00226          * a sequence of [integer (origin 1 node#), sequence of [octet-string]]
00227          * where the inner octet-string is the concatenated hashes on the merkle-path
00228          */
00229         res = ccn_ref_tagged_BLOB(CCN_DTAG_Witness, msg,
00230                                   co->offset[CCN_PCO_B_Witness],
00231                                   co->offset[CCN_PCO_E_Witness],
00232                                   &witness,
00233                                   &witness_size);
00234         if (res < 0)
00235             return (-1);
00236 
00237 
00238         digest_info = d2i_X509_SIG(NULL, &witness, witness_size);
00239         /* digest_info->algor->algorithm->{length, data}
00240          * digest_info->digest->{length, type, data}
00241          */
00242         /* ...2.2 is an MHT w/ SHA256 */
00243         ASN1_OBJECT *merkle_hash_tree_oid = OBJ_txt2obj("1.2.840.113550.11.1.2.2", 1);
00244         if (0 != OBJ_cmp(digest_info->algor->algorithm, merkle_hash_tree_oid)) {
00245             fprintf(stderr, "A witness is present without an MHT OID!\n");
00246             ASN1_OBJECT_free(merkle_hash_tree_oid);
00247             return (-1);
00248         }
00249         /* we're doing an MHT */
00250         ASN1_OBJECT_free(merkle_hash_tree_oid);
00251         merkle_path_digest = EVP_sha256();
00252         /* DER-encoded in the digest_info's digest ASN.1 octet string is the Merkle path info */
00253         merkle_path_info = d2i_MP_info(NULL, (const unsigned char **)&(digest_info->digest->data), digest_info->digest->length);
00254 #ifdef DEBUG
00255         int node = ASN1_INTEGER_get(merkle_path_info->node);
00256         int hash_count = sk_ASN1_OCTET_STRING_num(merkle_path_info->hashes);
00257         ASN1_OCTET_STRING *hash;
00258         fprintf(stderr, "A witness is present with an MHT OID\n");
00259         fprintf(stderr, "This is node %d, with %d hashes\n", node, hash_count);
00260         for (h = 0; h < hash_count; h++) {
00261             hash = sk_ASN1_OCTET_STRING_value(merkle_path_info->hashes, h);
00262             fprintf(stderr, "     hashes[%d] len = %d data = ", h, hash->length);
00263             for (x = 0; x < hash->length; x++) {
00264                 fprintf(stderr, "%02x", hash->data[x]);
00265             }
00266             fprintf(stderr, "\n");
00267         }
00268 #endif
00269         /* In the MHT signature case, we signed/verify the root hash */
00270         root_hash_size = EVP_MD_size(merkle_path_digest);
00271         root_hash = calloc(1, root_hash_size);
00272         res = ccn_merkle_root_hash(msg, size, co, merkle_path_digest, merkle_path_info, root_hash, root_hash_size);
00273         if (res < 0) return(-1);
00274         res = EVP_VerifyUpdate(ver_ctx, root_hash, root_hash_size);
00275         if (res == 0) return(-1);
00276         res = EVP_VerifyFinal(ver_ctx, signature_bits, signature_bits_size, pkey);
00277         EVP_MD_CTX_cleanup(ver_ctx);
00278     } else {
00279         /*
00280          * In the simple signature case, we signed/verify from the name through
00281          * the end of the content.
00282          */
00283         size_t signed_size = co->offset[CCN_PCO_E_Content] - co->offset[CCN_PCO_B_Name];
00284         res = EVP_VerifyUpdate(ver_ctx, msg + co->offset[CCN_PCO_B_Name], signed_size);
00285         if (res == 0) return(-1);
00286         res = EVP_VerifyFinal(ver_ctx, signature_bits, signature_bits_size, pkey);
00287         EVP_MD_CTX_cleanup(ver_ctx);
00288     }
00289     return (res);
00290 }
00291 
00292 struct ccn_pkey *
00293 ccn_d2i_pubkey(const unsigned char *p, size_t size)
00294 {
00295     const unsigned char *q = p;
00296     EVP_PKEY *ans;
00297     ans = d2i_PUBKEY(NULL, &q, size);
00298     return ((struct ccn_pkey *)ans);
00299 }
00300 
00301 void
00302 ccn_pubkey_free(struct ccn_pkey *i_pubkey)
00303 {
00304     EVP_PKEY *pkey = (EVP_PKEY *)i_pubkey;
00305     EVP_PKEY_free(pkey);
00306 }
00307 
00308 size_t
00309 ccn_pubkey_size(const struct ccn_pkey *i_pubkey)
00310 {
00311     size_t ans;
00312     EVP_PKEY *pkey = (EVP_PKEY *)i_pubkey;
00313     ans = EVP_PKEY_size(pkey);
00314     return (ans);
00315 }
00316 
00317 int
00318 ccn_append_pubkey_blob(struct ccn_charbuf *c, const struct ccn_pkey *i_pubkey)
00319 {
00320     int res;
00321     size_t bytes;
00322     unsigned char *p = NULL;
00323     res = i2d_PUBKEY((EVP_PKEY *)i_pubkey, NULL);
00324     if (res < 0)
00325         return(-1);
00326     bytes = res;
00327     res = ccn_charbuf_append_tt(c, bytes, CCN_BLOB);
00328     if (res < 0)
00329         return(-1);
00330     p = ccn_charbuf_reserve(c, bytes);
00331     if (p == NULL)
00332         return(-1);
00333     res = i2d_PUBKEY((EVP_PKEY *)i_pubkey, &p);
00334     if (res != (int)bytes)
00335         return(-1);
00336     c->length += bytes;
00337     return(bytes);
00338 }
00339 
00340 /* PRNG */
00341 
00342 /**
00343  * Generate pseudo-random bytes.
00344  *
00345  * @param buf is the destination buffer
00346  * @param size is in bytes
00347  */
00348 void
00349 ccn_random_bytes(unsigned char *buf, size_t size)
00350 {
00351     int num = size;
00352     
00353     if (num < 0 || num != size)
00354         abort();
00355     RAND_bytes(buf, num);
00356 }
00357 
00358 /**
00359  * Feed some entropy to the random number generator.
00360  * 
00361  * @param buf is the source buffer
00362  * @param size is in bytes
00363  * @param bits_of_entropy is an estimate; use 0 to make me guess
00364  */
00365 void
00366 ccn_add_entropy(const void *buf, size_t size, int bits_of_entropy)
00367 {
00368     int num = size;
00369     
00370     if (num < 0 || num != size)
00371         abort();
00372     /* Supply a hopefully conservative estimate of entropy. */
00373     if (bits_of_entropy <= 0)
00374         bits_of_entropy = (num < 32) ? 1 : num / 32;
00375     RAND_add((unsigned char *)buf, num, bits_of_entropy * 0.125);
00376 }

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