/** * Extend a Name with a new version stamp * @param h is the the ccn handle. * May be NULL. This procedure does not use the connection. * @param name is a ccnb-encoded Name prefix. By default it gets extended * in-place with one additional Component that conforms to the * versioning profile and is based on the supplied time, unless a * version component is already present. * @param versioning_flags modifies the default behavior: * CCN_V_REPLACE causes the last component to be replaced if it * appears to be a version stamp. If CCN_V_HIGH is set as well, an * attempt will be made to generate a new version stamp that is * later than the existing one, or to return an error. * CCN_V_NOW bases the version on the current time rather than the * supplied time. * CCN_V_NESTOK will allow the new version component to be appended * even if there is one there (this makes no difference if CCN_V_REPLACE * is also set). * @param secs is the desired time, in seconds since epoch * (ignored if CCN_V_NOW is set). * @param nsecs is the number of nanoseconds. * @returns -1 for error, 0 for success. */ int ccn_create_version(struct ccn *h, struct ccn_charbuf *name, int versioning_flags, intmax_t secs, int nsecs) { size_t i; size_t j; size_t lc = 0; size_t oc = 0; int n; struct ccn_indexbuf *nix = NULL; int myres = -1; int already_versioned = 0; int ok_flags = (CCN_V_REPLACE | CCN_V_HIGH | CCN_V_NOW | CCN_V_NESTOK); // XXX - right now we ignore h, but in the future we may use it to try to avoid non-monotonicies in the versions. nix = ccn_indexbuf_create(); n = ccn_name_split(name, nix); if (n < 0) goto Finish; if ((versioning_flags & ~ok_flags) != 0) goto Finish; /* Check for existing version component */ if (n >= 1) { oc = nix->buf[n-1]; lc = nix->buf[n] - oc; if (lc <= 11 && lc >= 6 && name->buf[oc + 2] == CCN_MARKER_VERSION) already_versioned = 1; } myres = 0; if (already_versioned && (versioning_flags & (CCN_V_REPLACE | CCN_V_NESTOK)) == 0) goto Finish; name->length -= 1; /* Strip name closer */ i = name->length; myres |= ccn_charbuf_append_tt(name, CCN_DTAG_Component, CCN_DTAG); if ((versioning_flags & CCN_V_NOW) != 0) myres |= ccnb_append_now_blob(name, CCN_MARKER_VERSION); else { myres |= ccnb_append_timestamp_blob(name, CCN_MARKER_VERSION, secs, nsecs); } myres |= ccn_charbuf_append_closer(name); /* </Component> */ if (myres < 0) { name->length = i; goto CloseName; } j = name->length; if (already_versioned && (versioning_flags & CCN_V_REPLACE) != 0) { oc = nix->buf[n-1]; lc = nix->buf[n] - oc; if ((versioning_flags & CCN_V_HIGH) != 0 && memcmp(name->buf + oc, name->buf + i, j - i) > 0) { /* Supplied version is in the future. */ name->length = i; // XXX - we could try harder to make this work, for now just error out myres = -1; goto CloseName; } memmove(name->buf + oc, name->buf + i, j - i); name->length -= lc; } CloseName: myres |= ccn_charbuf_append_closer(name); /* </Name> */ Finish: myres = (myres < 0) ? -1 : 0; ccn_indexbuf_destroy(&nix); return(myres); }
/** * Create SignedInfo. * * * @param c is used to hold the result. * @param publisher_key_id points to the digest of the publisher key id. * @param publisher_key_id_size is the size in bytes(32) of the pub key digest * @param timestamp holds the timestamp, as a ccnb-encoded blob, or is NULL to use the current time. * @param type indicates the Type of the ContentObject. * @param freshness is the FreshnessSeconds value, or -1 to omit. * @param finalblockid holds the FinalBlockID, as a ccnb-encoded blob, or is NULL to omit. * @param key_locator is the ccnb-encoded KeyLocator element, or NULL to omit. * @returns 0 for success or -1 for error. */ int ccn_signed_info_create(struct ccn_charbuf *c, const void *publisher_key_id, /* input, sha256 hash */ size_t publisher_key_id_size, /* input, 32 for sha256 hashes */ const struct ccn_charbuf *timestamp,/* input ccnb blob, NULL for "now" */ enum ccn_content_type type, /* input */ int freshness, /* input, -1 means omit */ const struct ccn_charbuf *finalblockid, /* input, NULL means omit */ const struct ccn_charbuf *key_locator) /* input, optional, ccnb encoded */ { int res = 0; const char fakepubkeyid[32] = {0}; if (publisher_key_id != NULL && publisher_key_id_size != 32) return(-1); res |= ccn_charbuf_append_tt(c, CCN_DTAG_SignedInfo, CCN_DTAG); res |= ccn_charbuf_append_tt(c, CCN_DTAG_PublisherPublicKeyDigest, CCN_DTAG); if (publisher_key_id != NULL) { res |= ccn_charbuf_append_tt(c, publisher_key_id_size, CCN_BLOB); res |= ccn_charbuf_append(c, publisher_key_id, publisher_key_id_size); } else { /* XXX - obtain the default publisher key id and append it */ res |= ccn_charbuf_append_tt(c, sizeof(fakepubkeyid), CCN_BLOB); res |= ccn_charbuf_append(c, fakepubkeyid, sizeof(fakepubkeyid)); } res |= ccn_charbuf_append_closer(c); res |= ccn_charbuf_append_tt(c, CCN_DTAG_Timestamp, CCN_DTAG); if (timestamp != NULL) res |= ccn_charbuf_append_charbuf(c, timestamp); else res |= ccnb_append_now_blob(c, CCN_MARKER_NONE); res |= ccn_charbuf_append_closer(c); if (type != CCN_CONTENT_DATA) { res |= ccn_charbuf_append_tt(c, CCN_DTAG_Type, CCN_DTAG); res |= ccn_charbuf_append_tt(c, 3, CCN_BLOB); res |= ccn_charbuf_append_value(c, type, 3); res |= ccn_charbuf_append_closer(c); } if (freshness >= 0) res |= ccnb_tagged_putf(c, CCN_DTAG_FreshnessSeconds, "%d", freshness); if (finalblockid != NULL) { res |= ccn_charbuf_append_tt(c, CCN_DTAG_FinalBlockID, CCN_DTAG); res |= ccn_charbuf_append_charbuf(c, finalblockid); res |= ccn_charbuf_append_closer(c); } if (key_locator != NULL) { /* key_locator is a sub-type that should already be encoded */ res |= ccn_charbuf_append_charbuf(c, key_locator); } res |= ccn_charbuf_append_closer(c); return(res == 0 ? 0 : -1); }