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];
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 
00134     /* input_hash[0, 1] = address of hash for (left,right) node of parent
00135      */
00136     while (node != 1) {
00137         input_hash[node & 1] = result;
00138         input_hash[(node & 1) ^ 1] = sk_ASN1_OCTET_STRING_value(merkle_path_info->hashes, hash_index)->data;
00139         if (sk_ASN1_OCTET_STRING_value(merkle_path_info->hashes, hash_index)->length != result_size)
00140             return (-1);
00141         hash_index -= 1;
00142 #ifdef DEBUG
00143         fprintf(stderr, "node[%d].lefthash = ", parent_of(node));
00144         for (int x = 0; x < result_size; x++) {
00145             fprintf(stderr, "%02x", input_hash[0][x]);
00146         }
00147         fprintf(stderr, "\n");
00148    
00149         fprintf(stderr, "node[%d].righthash = ", parent_of(node));
00150         for (int x = 0; x < result_size; x++) {
00151             fprintf(stderr, "%02x", input_hash[1][x]);
00152         }
00153         fprintf(stderr, "\n");
00154 #endif
00155         EVP_MD_CTX_init(digest_contextp);
00156         EVP_DigestInit_ex(digest_contextp, digest_type, NULL);
00157         res = EVP_DigestUpdate(digest_contextp, input_hash[0], result_size);
00158         res = EVP_DigestUpdate(digest_contextp, input_hash[1], result_size);
00159         res = EVP_DigestFinal_ex(digest_contextp, result, NULL);
00160         node = parent_of(node);
00161    
00162 #ifdef DEBUG
00163         fprintf(stderr, "yielding node[%d] hash = ", node);
00164         for (int x = 0; x < result_size; x++) {
00165             fprintf(stderr, "%02x", result[x]);
00166         }
00167         fprintf(stderr, "\n");
00168 #endif
00169     }
00170     return (0);
00171 }
00172 
00173 int ccn_verify_signature(const unsigned char *msg,
00174                      size_t size,
00175                      const struct ccn_parsed_ContentObject *co,
00176                      const struct ccn_pkey *verification_pubkey)
00177 {
00178     EVP_MD_CTX verc;
00179     EVP_MD_CTX *ver_ctx = &verc;
00180     X509_SIG *digest_info = NULL;
00181     MP_info *merkle_path_info = NULL;
00182     unsigned char *root_hash;
00183     size_t root_hash_size;
00184 
00185     int res;
00186 
00187     const EVP_MD *digest = EVP_md_null();
00188     const EVP_MD *merkle_path_digest = EVP_md_null();
00189 
00190     const unsigned char *signature_bits = NULL;
00191     size_t signature_bits_size = 0;
00192     const unsigned char *witness = NULL;
00193     size_t witness_size = 0;
00194     EVP_PKEY *pkey = (EVP_PKEY *)verification_pubkey;
00195 #ifdef DEBUG
00196     int x, h;
00197 #endif
00198 
00199     res = ccn_ref_tagged_BLOB(CCN_DTAG_SignatureBits, msg,
00200                               co->offset[CCN_PCO_B_SignatureBits],
00201                               co->offset[CCN_PCO_E_SignatureBits],
00202                               &signature_bits,
00203                               &signature_bits_size);
00204     if (res < 0)
00205         return (-1);
00206 
00207     if (co->offset[CCN_PCO_B_DigestAlgorithm] == co->offset[CCN_PCO_E_DigestAlgorithm]) {
00208         digest = EVP_sha256();
00209     }
00210     else {
00211         /* XXX - figure out what algorithm the OID represents */
00212         fprintf(stderr, "not a DigestAlgorithm I understand right now\n");
00213         return (-1);
00214     }
00215 
00216     EVP_MD_CTX_init(ver_ctx);
00217     res = EVP_VerifyInit_ex(ver_ctx, digest, NULL);
00218     if (!res)
00219         return (-1);
00220 
00221     if (co->offset[CCN_PCO_B_Witness] != co->offset[CCN_PCO_E_Witness]) {
00222         /* The witness is a DigestInfo, where the octet-string therein encapsulates
00223          * a sequence of [integer (origin 1 node#), sequence of [octet-string]]
00224          * where the inner octet-string is the concatenated hashes on the merkle-path
00225          */
00226         res = ccn_ref_tagged_BLOB(CCN_DTAG_Witness, msg,
00227                                   co->offset[CCN_PCO_B_Witness],
00228                                   co->offset[CCN_PCO_E_Witness],
00229                                   &witness,
00230                                   &witness_size);
00231         if (res < 0)
00232             return (-1);
00233 
00234 
00235         digest_info = d2i_X509_SIG(NULL, &witness, witness_size);
00236         /* digest_info->algor->algorithm->{length, data}
00237          * digest_info->digest->{length, type, data}
00238          */
00239         /* ...2.2 is an MHT w/ SHA256 */
00240         ASN1_OBJECT *merkle_hash_tree_oid = OBJ_txt2obj("1.2.840.113550.11.1.2.2", 1);
00241         if (0 != OBJ_cmp(digest_info->algor->algorithm, merkle_hash_tree_oid)) {
00242             fprintf(stderr, "A witness is present without an MHT OID!\n");
00243             ASN1_OBJECT_free(merkle_hash_tree_oid);
00244             return (-1);
00245         }
00246         /* we're doing an MHT */
00247         ASN1_OBJECT_free(merkle_hash_tree_oid);
00248         merkle_path_digest = EVP_sha256();
00249         /* DER-encoded in the digest_info's digest ASN.1 octet string is the Merkle path info */
00250         merkle_path_info = d2i_MP_info(NULL, (const unsigned char **)&(digest_info->digest->data), digest_info->digest->length);
00251 #ifdef DEBUG
00252         int node = ASN1_INTEGER_get(merkle_path_info->node);
00253         int hash_count = sk_ASN1_OCTET_STRING_num(merkle_path_info->hashes);
00254         ASN1_OCTET_STRING *hash;
00255         fprintf(stderr, "A witness is present with an MHT OID\n");
00256         fprintf(stderr, "This is node %d, with %d hashes\n", node, hash_count);
00257         for (h = 0; h < hash_count; h++) {
00258             hash = sk_ASN1_OCTET_STRING_value(merkle_path_info->hashes, h);
00259             fprintf(stderr, "     hashes[%d] len = %d data = ", h, hash->length);
00260             for (x = 0; x < hash->length; x++) {
00261                 fprintf(stderr, "%02x", hash->data[x]);
00262             }
00263             fprintf(stderr, "\n");
00264         }
00265 #endif
00266         /* In the MHT signature case, we signed/verify the root hash */
00267         root_hash_size = EVP_MD_size(merkle_path_digest);
00268         root_hash = calloc(1, root_hash_size);
00269         res = ccn_merkle_root_hash(msg, size, co, merkle_path_digest, merkle_path_info, root_hash, root_hash_size);
00270         res = EVP_VerifyUpdate(ver_ctx, root_hash, root_hash_size);
00271         res = EVP_VerifyFinal(ver_ctx, signature_bits, signature_bits_size, pkey);
00272         EVP_MD_CTX_cleanup(ver_ctx);
00273     } else {
00274         /*
00275          * In the simple signature case, we signed/verify from the name through
00276          * the end of the content.
00277          */
00278         size_t signed_size = co->offset[CCN_PCO_E_Content] - co->offset[CCN_PCO_B_Name];
00279         res = EVP_VerifyUpdate(ver_ctx, msg + co->offset[CCN_PCO_B_Name], signed_size);
00280         res = EVP_VerifyFinal(ver_ctx, signature_bits, signature_bits_size, pkey);
00281         EVP_MD_CTX_cleanup(ver_ctx);
00282     }
00283 
00284     if (res == 1)
00285         return (1);
00286     else
00287         return (0);
00288 }
00289 
00290 struct ccn_pkey *
00291 ccn_d2i_pubkey(const unsigned char *p, size_t size)
00292 {
00293     const unsigned char *q = p;
00294     EVP_PKEY *ans;
00295     ans = d2i_PUBKEY(NULL, &q, size);
00296     return ((struct ccn_pkey *)ans);
00297 }
00298 
00299 void
00300 ccn_pubkey_free(struct ccn_pkey *i_pubkey)
00301 {
00302     EVP_PKEY *pkey = (EVP_PKEY *)i_pubkey;
00303     EVP_PKEY_free(pkey);
00304 }
00305 
00306 size_t
00307 ccn_pubkey_size(const struct ccn_pkey *i_pubkey)
00308 {
00309     size_t ans;
00310     EVP_PKEY *pkey = (EVP_PKEY *)i_pubkey;
00311     ans = EVP_PKEY_size(pkey);
00312     return (ans);
00313 }
00314 
00315 int
00316 ccn_append_pubkey_blob(struct ccn_charbuf *c, const struct ccn_pkey *i_pubkey)
00317 {
00318     int res;
00319     size_t bytes;
00320     unsigned char *p = NULL;
00321     res = i2d_PUBKEY((EVP_PKEY *)i_pubkey, NULL);
00322     if (res < 0)
00323         return(-1);
00324     bytes = res;
00325     res = ccn_charbuf_append_tt(c, bytes, CCN_BLOB);
00326     if (res < 0)
00327         return(-1);
00328     p = ccn_charbuf_reserve(c, bytes);
00329     if (p == NULL)
00330         return(-1);
00331     res = i2d_PUBKEY((EVP_PKEY *)i_pubkey, &p);
00332     if (res != (int)bytes)
00333         return(-1);
00334     c->length += bytes;
00335     return(bytes);
00336 }
00337 
00338 /* PRNG */
00339 
00340 /**
00341  * Generate pseudo-random bytes.
00342  *
00343  * @param buf is the destination buffer
00344  * @param size is in bytes
00345  */
00346 void
00347 ccn_random_bytes(unsigned char *buf, size_t size)
00348 {
00349     int num = size;
00350     
00351     if (num < 0 || num != size)
00352         abort();
00353     RAND_bytes(buf, num);
00354 }
00355 
00356 /**
00357  * Feed some entropy to the random number generator.
00358  * 
00359  * @param buf is the source buffer
00360  * @param size is in bytes
00361  * @param bits_of_entropy is an estimate; use 0 to make me guess
00362  */
00363 void
00364 ccn_add_entropy(const void *buf, size_t size, int bits_of_entropy)
00365 {
00366     int num = size;
00367     
00368     if (num < 0 || num != size)
00369         abort();
00370     /* Supply a hopefully conservative estimate of entropy. */
00371     if (bits_of_entropy <= 0)
00372         bits_of_entropy = (num < 32) ? 1 : num / 32;
00373     RAND_add((unsigned char *)buf, num, bits_of_entropy * 0.125);
00374 }
Generated on Fri May 13 16:27:03 2011 for Content-Centric Networking in C by  doxygen 1.6.3