ccn_buf_encoder.c

Go to the documentation of this file.
00001 /**
00002  * @file ccn_buf_encoder.c
00003  * @brief Support for constructing various ccnb-encoded objects.
00004  * 
00005  * Part of the CCNx C Library.
00006  *
00007  * Copyright (C) 2008, 2009, 2011 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 <string.h>
00021 #include <stdarg.h>
00022 #include <stdio.h>
00023 #include <stdlib.h>
00024 #include <sys/time.h>
00025 #include <ccn/ccn.h>
00026 #include <ccn/charbuf.h>
00027 #include <ccn/coding.h>
00028 #include <ccn/indexbuf.h>
00029 #include <ccn/signing.h>
00030 #include <ccn/ccn_private.h>
00031 
00032 /**
00033  * Create SignedInfo.
00034  *
00035  * @param c is used to hold the result.
00036  * @param publisher_key_id points to the digest of the publisher key id.
00037  * @param publisher_key_id_size is the size in bytes(32) of the pub key digest
00038  * @param timestamp holds the timestamp, as a ccnb-encoded blob, or is NULL
00039           to use the current time.
00040  * @param type indicates the Type of the ContentObject.
00041  * @param freshness is the FreshnessSeconds value, or -1 to omit.
00042  * @param finalblockid holds the FinalBlockID, as a ccnb-encoded blob, or is
00043           NULL to omit.
00044  * @param key_locator is the ccnb-encoded KeyLocator element, or NULL to omit.
00045  * @returns 0 for success or -1 for error.
00046  */
00047 int
00048 ccn_signed_info_create(struct ccn_charbuf *c,
00049                        const void *publisher_key_id,    /* input, sha256 hash */
00050                        size_t publisher_key_id_size,    /* input, 32 for sha256 hashes */
00051                        const struct ccn_charbuf *timestamp,/* input ccnb blob, NULL for "now" */
00052                        enum ccn_content_type type,      /* input */
00053                        int freshness,                   /* input, -1 means omit */
00054                        const struct ccn_charbuf *finalblockid,  /* input, NULL means omit */
00055                        const struct ccn_charbuf *key_locator)   /* input, optional, ccnb encoded */
00056 {
00057     int res = 0;
00058     const char fakepubkeyid[32] = {0};
00059  
00060     if (publisher_key_id != NULL && publisher_key_id_size != 32)
00061         return(-1);
00062 
00063     res |= ccn_charbuf_append_tt(c, CCN_DTAG_SignedInfo, CCN_DTAG);
00064 
00065     res |= ccn_charbuf_append_tt(c, CCN_DTAG_PublisherPublicKeyDigest, CCN_DTAG);
00066     if (publisher_key_id != NULL) {
00067         res |= ccn_charbuf_append_tt(c, publisher_key_id_size, CCN_BLOB);
00068         res |= ccn_charbuf_append(c, publisher_key_id, publisher_key_id_size);
00069     } else {
00070         /* XXX - obtain the default publisher key id and append it */
00071         res |= ccn_charbuf_append_tt(c, sizeof(fakepubkeyid), CCN_BLOB);
00072         res |= ccn_charbuf_append(c, fakepubkeyid, sizeof(fakepubkeyid));
00073     }
00074     res |= ccn_charbuf_append_closer(c);
00075 
00076     res |= ccn_charbuf_append_tt(c, CCN_DTAG_Timestamp, CCN_DTAG);
00077     if (timestamp != NULL)
00078         res |= ccn_charbuf_append_charbuf(c, timestamp);
00079     else
00080         res |= ccnb_append_now_blob(c, CCN_MARKER_NONE);
00081     res |= ccn_charbuf_append_closer(c);
00082 
00083     if (type != CCN_CONTENT_DATA) {
00084         res |= ccn_charbuf_append_tt(c, CCN_DTAG_Type, CCN_DTAG);
00085         res |= ccn_charbuf_append_tt(c, 3, CCN_BLOB);
00086         res |= ccn_charbuf_append_value(c, type, 3);
00087         res |= ccn_charbuf_append_closer(c);
00088     }
00089 
00090     if (freshness >= 0)
00091         res |= ccnb_tagged_putf(c, CCN_DTAG_FreshnessSeconds, "%d", freshness);
00092 
00093     if (finalblockid != NULL) {
00094         res |= ccn_charbuf_append_tt(c, CCN_DTAG_FinalBlockID, CCN_DTAG);
00095         res |= ccn_charbuf_append_charbuf(c, finalblockid);
00096         res |= ccn_charbuf_append_closer(c);
00097     }
00098 
00099     if (key_locator != NULL) {
00100         /* key_locator is a sub-type that should already be encoded */
00101         res |= ccn_charbuf_append_charbuf(c, key_locator);
00102     }
00103     
00104     res |= ccn_charbuf_append_closer(c);
00105 
00106     return(res == 0 ? 0 : -1);
00107 }
00108 
00109 static int
00110 ccn_encode_Signature(struct ccn_charbuf *buf,
00111                      const char *digest_algorithm,
00112                      const void *witness,
00113                      size_t witness_size,
00114                      const struct ccn_signature *signature,
00115                      size_t signature_size)
00116 {
00117     int res = 0;
00118 
00119     if (signature == NULL)
00120         return(-1);
00121 
00122     res |= ccn_charbuf_append_tt(buf, CCN_DTAG_Signature, CCN_DTAG);
00123 
00124     if (digest_algorithm != NULL) {
00125         res |= ccn_charbuf_append_tt(buf, CCN_DTAG_DigestAlgorithm, CCN_DTAG);
00126         res |= ccn_charbuf_append_tt(buf, strlen(digest_algorithm), CCN_UDATA);
00127         res |= ccn_charbuf_append_string(buf, digest_algorithm);
00128         res |= ccn_charbuf_append_closer(buf);
00129     }
00130 
00131     if (witness != NULL) {
00132         res |= ccn_charbuf_append_tt(buf, CCN_DTAG_Witness, CCN_DTAG);
00133         res |= ccn_charbuf_append_tt(buf, witness_size, CCN_BLOB);
00134         res |= ccn_charbuf_append(buf, witness, witness_size);
00135         res |= ccn_charbuf_append_closer(buf);
00136     }
00137 
00138     res |= ccn_charbuf_append_tt(buf, CCN_DTAG_SignatureBits, CCN_DTAG);
00139     res |= ccn_charbuf_append_tt(buf, signature_size, CCN_BLOB);
00140     res |= ccn_charbuf_append(buf, signature, signature_size);
00141     res |= ccn_charbuf_append_closer(buf);
00142     
00143     res |= ccn_charbuf_append_closer(buf);
00144 
00145     return(res == 0 ? 0 : -1);
00146 }
00147 
00148 /**
00149  * Encode and sign a ContentObject.
00150  * @param buf is the output buffer where encoded object is written.
00151  * @param Name is the ccnb-encoded name from ccn_name_init and friends.
00152  * @param SignedInfo is the ccnb-encoded info from ccn_signed_info_create.
00153  * @param data pintes to the raw data to be encoded.
00154  * @param size is the size, in bytes, of the raw data to be encoded.
00155  * @param digest_algorithm may be NULL for default.
00156  * @param private_key is the private key to use for signing.
00157  * @returns 0 for success or -1 for error.
00158  */
00159 int
00160 ccn_encode_ContentObject(struct ccn_charbuf *buf,
00161                          const struct ccn_charbuf *Name,
00162                          const struct ccn_charbuf *SignedInfo,
00163                          const void *data,
00164                          size_t size,
00165                          const char *digest_algorithm,
00166                          const struct ccn_pkey *private_key
00167                          )
00168 {
00169     int res = 0;
00170     struct ccn_sigc *sig_ctx;
00171     struct ccn_signature *signature;
00172     size_t signature_size;
00173     struct ccn_charbuf *content_header;
00174     size_t closer_start;
00175 
00176     content_header = ccn_charbuf_create();
00177     res |= ccn_charbuf_append_tt(content_header, CCN_DTAG_Content, CCN_DTAG);
00178     if (size != 0)
00179         res |= ccn_charbuf_append_tt(content_header, size, CCN_BLOB);
00180     closer_start = content_header->length;
00181     res |= ccn_charbuf_append_closer(content_header);
00182     if (res < 0)
00183         return(-1);
00184     sig_ctx = ccn_sigc_create();
00185     if (sig_ctx == NULL)
00186         return(-1);
00187     if (0 != ccn_sigc_init(sig_ctx, digest_algorithm))
00188         return(-1);
00189     if (0 != ccn_sigc_update(sig_ctx, Name->buf, Name->length))
00190         return(-1);
00191     if (0 != ccn_sigc_update(sig_ctx, SignedInfo->buf, SignedInfo->length))
00192         return(-1);
00193     if (0 != ccn_sigc_update(sig_ctx, content_header->buf, closer_start))
00194         return(-1);
00195     if (0 != ccn_sigc_update(sig_ctx, data, size))
00196         return(-1);
00197     if (0 != ccn_sigc_update(sig_ctx, content_header->buf + closer_start,
00198                              content_header->length - closer_start))
00199         return(-1);
00200     signature = calloc(1, ccn_sigc_signature_max_size(sig_ctx, private_key));
00201     if (signature == NULL)
00202         return(-1);
00203     res = ccn_sigc_final(sig_ctx, signature, &signature_size, private_key);
00204     if (0 != res) {
00205         free(signature);
00206         return(-1);
00207     }
00208     ccn_sigc_destroy(&sig_ctx);
00209     res |= ccn_charbuf_append_tt(buf, CCN_DTAG_ContentObject, CCN_DTAG);
00210     res |= ccn_encode_Signature(buf, digest_algorithm,
00211                                 NULL, 0, signature, signature_size);
00212     res |= ccn_charbuf_append_charbuf(buf, Name);
00213     res |= ccn_charbuf_append_charbuf(buf, SignedInfo);
00214     res |= ccnb_append_tagged_blob(buf, CCN_DTAG_Content, data, size);
00215     res |= ccn_charbuf_append_closer(buf);
00216     free(signature);
00217     ccn_charbuf_destroy(&content_header);
00218     return(res == 0 ? 0 : -1);
00219 }
00220 
00221 /***********************************
00222  * Append a StatusResponse
00223  * 
00224  *  @param buf is the buffer to append to.
00225  *  @param errcode is a 3-digit error code.
00226  *            It should be documented in StatusResponse.txt.
00227  *  @param errtext is human-readable text (may be NULL).
00228  *  @returns 0 for success or -1 for error.
00229  */
00230 int
00231 ccn_encode_StatusResponse(struct ccn_charbuf *buf,
00232                           int errcode, const char *errtext)
00233 {
00234     int res = 0;
00235     if (errcode < 100 || errcode > 999)
00236         return(-1);
00237     res |= ccn_charbuf_append_tt(buf, CCN_DTAG_StatusResponse, CCN_DTAG);
00238     res |= ccnb_tagged_putf(buf, CCN_DTAG_StatusCode, "%d", errcode);
00239     if (errtext != NULL && errtext[0] != 0)
00240         res |= ccnb_tagged_putf(buf, CCN_DTAG_StatusText, "%s", errtext);
00241     res |= ccn_charbuf_append_closer(buf);
00242     return(res);
00243 }
00244 
00245 /**
00246  * Append a ccnb start marker
00247  *
00248  * This forms the basic building block of ccnb-encoded data.
00249  * @param c is the buffer to append to.
00250  * @param val is the numval, intepreted according to tt (see enum ccn_tt).
00251  * @param tt is the type field.
00252  * @returns 0 for success or -1 for error.
00253  */
00254 int
00255 ccn_charbuf_append_tt(struct ccn_charbuf *c, size_t val, enum ccn_tt tt)
00256 {
00257     unsigned char buf[1+8*((sizeof(val)+6)/7)];
00258     unsigned char *p = &(buf[sizeof(buf)-1]);
00259     int n = 1;
00260     p[0] = (CCN_TT_HBIT & ~CCN_CLOSE) |
00261            ((val & CCN_MAX_TINY) << CCN_TT_BITS) |
00262            (CCN_TT_MASK & tt);
00263     val >>= (7-CCN_TT_BITS);
00264     while (val != 0) {
00265         (--p)[0] = (((unsigned char)val) & ~CCN_TT_HBIT) | CCN_CLOSE;
00266         n++;
00267         val >>= 7;
00268     }
00269     return(ccn_charbuf_append(c, p, n));
00270 }
00271 
00272 int
00273 ccn_charbuf_append_closer(struct ccn_charbuf *c)
00274 {
00275     int res;
00276     const unsigned char closer = CCN_CLOSE;
00277     res = ccn_charbuf_append(c, &closer, 1);
00278     return(res);
00279 }
00280 
00281 /**
00282  * Append a non-negative integer as a UDATA.
00283  * @param c is the buffer to append to.
00284  * @param nni is a non-negative value.
00285  * @returns 0 for success or -1 for error.
00286  */
00287 int
00288 ccnb_append_number(struct ccn_charbuf *c, int nni)
00289 {
00290     char nnistring[40];
00291     int nnistringlen;
00292     int res;
00293 
00294     if (nni < 0)
00295         return(-1);
00296     nnistringlen = snprintf(nnistring, sizeof(nnistring), "%d", nni);
00297     if (nnistringlen >= sizeof(nnistring))
00298         return(-1);
00299     res = ccn_charbuf_append_tt(c, nnistringlen, CCN_UDATA);
00300     res |= ccn_charbuf_append_string(c, nnistring);
00301     return(res);
00302 }
00303 
00304 /**
00305  * Append a binary timestamp
00306  * as a BLOB using the ccn binary Timestamp representation (12-bit fraction).
00307  * @param c is the buffer to append to.
00308  * @param marker
00309  *   If marker >= 0, the low-order byte is used as a marker byte, useful for
00310  *   some content naming conventions (versioning, in particular).
00311  * @param secs - seconds since epoch
00312  * @param nsecs - nanoseconds
00313  * @returns 0 for success or -1 for error.
00314  */
00315 int
00316 ccnb_append_timestamp_blob(struct ccn_charbuf *c,
00317                            enum ccn_marker marker,
00318                            intmax_t secs, int nsecs)
00319 {
00320     int i;
00321     int n;
00322     intmax_t ts;
00323     unsigned char *p;
00324     if (secs <= 0 || nsecs < 0 || nsecs > 999999999)
00325         return(-1);
00326     n = 2;
00327     for (ts = secs >> 4; n < 7 && ts != 0; ts >>= 8)
00328         n++;
00329     ccn_charbuf_append_tt(c, n + (marker >= 0), CCN_BLOB);
00330     if (marker >= 0)
00331         ccn_charbuf_append_value(c, marker, 1);
00332     p = ccn_charbuf_reserve(c, n);
00333     if (p == NULL)
00334         return(-1);
00335     ts = secs >> 4;
00336     for (i = 0; i < n - 2; i++)
00337         p[i] = ts >> (8 * (n - 3 - i));
00338     /* arithmetic contortions are to avoid overflowing 31 bits */
00339     ts = ((secs & 15) << 12) + ((nsecs / 5 * 8 + 195312) / 390625);
00340     for (i = n - 2; i < n; i++)
00341         p[i] = ts >> (8 * (n - 1 - i));
00342     c->length += n;
00343     return(0);
00344 }
00345 
00346 /**
00347  * Append a binary timestamp, using the current time.
00348  * 
00349  * Like ccnb_append_timestamp_blob() but uses current time
00350  * @param c is the buffer to append to.
00351  * @param marker - see ccnb_append_timestamp_blob()
00352  * @returns 0 for success or -1 for error.
00353  */
00354 int
00355 ccnb_append_now_blob(struct ccn_charbuf *c, enum ccn_marker marker)
00356 {
00357     struct timeval now;
00358     int res;
00359 
00360     gettimeofday(&now, NULL);
00361     res = ccnb_append_timestamp_blob(c, marker, now.tv_sec, now.tv_usec * 1000);
00362     return(res);
00363 }
00364 
00365 /**
00366  * Append a start-of-element marker.
00367  */
00368 int
00369 ccnb_element_begin(struct ccn_charbuf *c, enum ccn_dtag dtag)
00370 {
00371     return(ccn_charbuf_append_tt(c, dtag, CCN_DTAG));
00372 }
00373 
00374 /**
00375  * Append an end-of-element marker.
00376  *
00377  * This is the same as ccn_charbuf_append_closer()
00378  */
00379 int ccnb_element_end(struct ccn_charbuf *c)
00380 {
00381     return(ccn_charbuf_append_closer(c));
00382 }
00383 
00384 /**
00385  * Append a tagged BLOB
00386  *
00387  * This is a ccnb-encoded element with containing the BLOB as content
00388  * @param c is the buffer to append to.
00389  * @param dtag is the element's dtab
00390  * @param data points to the binary data
00391  * @param size is the size of the data, in bytes
00392  * @returns 0 for success or -1 for error.
00393  */
00394 int
00395 ccnb_append_tagged_blob(struct ccn_charbuf *c,
00396                         enum ccn_dtag dtag,
00397                         const void *data,
00398                         size_t size)
00399 {
00400     int res;
00401 
00402     res = ccn_charbuf_append_tt(c, dtag, CCN_DTAG);
00403     if (size != 0) {
00404         res |= ccn_charbuf_append_tt(c, size, CCN_BLOB);
00405         res |= ccn_charbuf_append(c, data, size);
00406     }
00407     res |= ccn_charbuf_append_closer(c);
00408     return(res == 0 ? 0 : -1);
00409 }
00410 
00411 /**
00412  * Append a tagged UDATA string, with printf-style formatting
00413  *
00414  * This is a ccnb-encoded element with containing UDATA as content.
00415  * @param c is the buffer to append to.
00416  * @param dtag is the element's dtab.
00417  * @param fmt is a printf-style format string, followed by its values
00418  * @returns 0 for success or -1 for error.
00419  */
00420 int
00421 ccnb_tagged_putf(struct ccn_charbuf *c,
00422                  enum ccn_dtag dtag, const char *fmt, ...)
00423 {
00424     int res;
00425     int size;
00426     va_list ap;
00427     char *ptr;
00428     
00429     res = ccn_charbuf_append_tt(c, dtag, CCN_DTAG);
00430     if (res < 0)
00431         return(-1);
00432     ptr = (char *)ccn_charbuf_reserve(c, strlen(fmt) + 20);
00433     if (ptr == NULL)
00434         return(-1);
00435     va_start(ap, fmt);
00436     size = vsnprintf(ptr + 2, (c->limit - c->length - 2), fmt, ap);
00437     va_end(ap);
00438     if (size < 0)
00439         return(-1);
00440     if (size > 0) {
00441         if (size >= (c->limit - c->length - 2))
00442             ptr = NULL;
00443         res |= ccn_charbuf_append_tt(c, size, CCN_UDATA);
00444         if (ptr == (char *)c->buf + c->length + 2)
00445             c->length += size;
00446         else if (ptr == (char *)c->buf + c->length + 1) {
00447             memmove(ptr - 1, ptr, size);
00448             c->length += size;
00449         }
00450         else {
00451             ptr = (char *)ccn_charbuf_reserve(c, size + 1);
00452             va_start(ap, fmt);
00453             size = vsnprintf(ptr, size + 1, fmt, ap);
00454             va_end(ap);
00455             if (size < 0)
00456                 return(-1);
00457             c->length += size;
00458         }
00459     }
00460     res |= ccn_charbuf_append_closer(c);
00461     return(res == 0 ? 0 : -1);    
00462 }
00463 
Generated on Fri May 13 16:27:02 2011 for Content-Centric Networking in C by  doxygen 1.6.3