/** * Advance the last Component of a Name to the next possible value. * @param c contains a ndnb-encoded Name to be updated. * @returns -1 for error, otherwise the number of Components */ int ndn_name_next_sibling(struct ndn_charbuf *c) { int res = -1; struct ndn_indexbuf *ndx; unsigned char *lastcomp = NULL; size_t lastcompsize = 0; size_t i; int carry; struct ndn_charbuf *newcomp; ndx = ndn_indexbuf_create(); if (ndx == NULL) goto Finish; res = ndn_name_split(c, ndx); if (res <= 0) { res = -1; goto Finish; } res = ndn_ref_tagged_BLOB(NDN_DTAG_Component, c->buf, ndx->buf[res-1], ndx->buf[res], (const unsigned char **)&lastcomp, &lastcompsize); if (res < 0) goto Finish; for (carry = 1, i = lastcompsize; carry && i > 0; i--) { carry = (((++lastcomp[i-1]) & 0xFF) == 0x00); } if (carry) { newcomp = ndn_charbuf_create(); res |= ndn_charbuf_append_value(newcomp, 0, 1); res |= ndn_charbuf_append(newcomp, lastcomp, lastcompsize); res |= ndn_name_chop(c, ndx, ndx->n - 2); res |= ndn_name_append(c, newcomp->buf, newcomp->length); ndn_charbuf_destroy(&newcomp); if (res < 0) goto Finish; } res = ndx->n - 1; Finish: ndn_indexbuf_destroy(&ndx); return(res); }
PyObject * KeyLocator_obj_from_ndn(PyObject *py_keylocator) { struct ndn_buf_decoder decoder, *d; struct ndn_charbuf *keylocator; struct ndn_charbuf *name; struct ndn_pkey *pubkey; size_t start, stop; int r; PyObject *py_o; PyObject *py_KeyLocator_obj = NULL; keylocator = NDNObject_Get(KEY_LOCATOR, py_keylocator); debug("KeyLocator_from_ndn start\n"); d = ndn_buf_decoder_start(&decoder, keylocator->buf, keylocator->length); assert(d); //should always succeed if (!ndn_buf_match_dtag(d, NDN_DTAG_KeyLocator)) { PyErr_SetString(g_PyExc_NDNKeyLocatorError, "The input isn't a valid" " KeyLocator"); return NULL; } ndn_buf_advance(d); if (ndn_buf_match_dtag(d, NDN_DTAG_KeyName)) { const unsigned char *bname; size_t bname_size; PyObject *py_name_obj; ndn_buf_advance(d); start = d->decoder.token_index; r = ndn_parse_Name(d, NULL); stop = d->decoder.token_index; if (r < 0) return PyErr_Format(g_PyExc_NDNKeyLocatorError, "Error finding" " NDN_DTAG_Name for KeyName (decoder state: %d)", d->decoder.state); assert(stop > start); bname_size = stop - start; bname = d->buf + start; /* r = ndn_ref_tagged_BLOB(NDN_DTAG_Name, d->buf, start, stop, &bname, &bname_size); if (r < 0) return PyErr_Format(g_PyExc_NDNKeyLocatorError, "Error getting" " NDN_DTAG_Name BLOB for KeyName (decoder state: %d)", d->decoder.state); */ debug("Parse NDN_DTAG_Name inside KeyName, len=%zd\n", bname_size); py_o = NDNObject_New_charbuf(NAME, &name); if (!py_o) return NULL; r = ndn_charbuf_append(name, bname, bname_size); if (r < 0) { Py_DECREF(py_o); return PyErr_NoMemory(); } py_name_obj = Name_obj_from_ndn(py_o); Py_DECREF(py_o); if (!py_name_obj) return NULL; py_KeyLocator_obj = PyObject_CallObject(g_type_KeyLocator, NULL); if (!py_KeyLocator_obj) { Py_DECREF(py_name_obj); goto error; } r = PyObject_SetAttrString(py_KeyLocator_obj, "keyName", py_name_obj); Py_DECREF(py_name_obj); JUMP_IF_NEG(r, error); #pragma message "Parse and add digest to the keylocator" } else if (ndn_buf_match_dtag(d, NDN_DTAG_Key)) { const unsigned char *dkey; size_t dkey_size; PyObject *py_key_obj, *py_ndn_key; start = d->decoder.token_index; r = ndn_parse_required_tagged_BLOB(d, NDN_DTAG_Key, 1, -1); stop = d->decoder.token_index; if (r < 0) return PyErr_Format(g_PyExc_NDNKeyLocatorError, "Error finding" " NDN_DTAG_Key for Key (decoder state: %d)", d->decoder.state); r = ndn_ref_tagged_BLOB(NDN_DTAG_Key, d->buf, start, stop, &dkey, &dkey_size); if (r < 0) return PyErr_Format(g_PyExc_NDNKeyLocatorError, "Error getting" " NDN_DTAG_Key BLOB for Key (decoder state: %d)", d->decoder.state); debug("Parse NDN_DTAG_Key, len=%zd\n", dkey_size); pubkey = ndn_d2i_pubkey(dkey, dkey_size); // free with ndn_pubkey_free() if (!pubkey) { PyErr_SetString(g_PyExc_NDNKeyLocatorError, "Unable to parse key to" " internal representation"); return NULL; } py_ndn_key = NDNObject_New(PKEY_PUB, pubkey); if (!py_ndn_key) { ndn_pubkey_free(pubkey); return NULL; } py_key_obj = Key_obj_from_ndn(py_ndn_key); Py_DECREF(py_ndn_key); if (!py_key_obj) return NULL; py_KeyLocator_obj = PyObject_CallObject(g_type_KeyLocator, NULL); if (!py_KeyLocator_obj) { Py_DECREF(py_key_obj); goto error; } r = PyObject_SetAttrString(py_KeyLocator_obj, "key", py_key_obj); Py_DECREF(py_key_obj); JUMP_IF_NEG(r, error); } else if (ndn_buf_match_dtag(d, NDN_DTAG_Certificate)) { PyErr_SetString(PyExc_NotImplementedError, "Found certificate DTAG," " which currently is unsupported"); return NULL; } else { PyErr_SetString(g_PyExc_NDNKeyLocatorError, "Unknown KeyLocator Type"); return NULL; } ndn_buf_check_close(d); // we don't really check the parser, though- return py_KeyLocator_obj; error: Py_XDECREF(py_KeyLocator_obj); return NULL; }
/** * Load a link to the repo policy from the repoPolicy file and load the link * target to extract the actual policy. * If a policy file does not exist a new one is created, with a link to a policy * based either on the environment variable NDNR_GLOBAL_PREFIX or the system * default value of ndn:/named-data.net/ndn/Repos, plus the system defaults for * other fields. * This routine must be called after the btree code is initialized and capable * of returning content objects. * Sets the parsed_policy field of the handle to be the new policy. */ static int load_policy(struct ndnr_handle *ndnr) { int fd; ssize_t res; struct content_entry *content = NULL; const unsigned char *content_msg = NULL; struct ndn_parsed_ContentObject pco = {0}; struct ndn_parsed_Link pl = {0}; struct ndn_indexbuf *nc = NULL; struct ndn_charbuf *basename = NULL; struct ndn_charbuf *policy = NULL; struct ndn_charbuf *policy_cob = NULL; struct ndn_charbuf *policyFileName; const char *global_prefix; const unsigned char *buf = NULL; size_t length = 0; int segment = 0; int final = 0; struct ndn_buf_decoder decoder; struct ndn_buf_decoder *d; policyFileName = ndn_charbuf_create(); ndn_charbuf_putf(policyFileName, "%s/repoPolicy", ndnr->directory); ndnr->parsed_policy = ndnr_parsed_policy_create(); fd = open(ndn_charbuf_as_string(policyFileName), O_RDONLY); if (fd >= 0) { ndnr->policy_link_cob = ndn_charbuf_create(); ndn_charbuf_reserve(ndnr->policy_link_cob, 4096); // limits the size of the policy link ndnr->policy_link_cob->length = 0; // clear the buffer res = read(fd, ndnr->policy_link_cob->buf, ndnr->policy_link_cob->limit - ndnr->policy_link_cob->length); close(fd); if (res == -1) { r_init_fail(ndnr, __LINE__, "Error reading repoPolicy file.", errno); ndn_charbuf_destroy(&ndnr->policy_link_cob); ndn_charbuf_destroy(&policyFileName); return(-1); } ndnr->policy_link_cob->length = res; nc = ndn_indexbuf_create(); res = ndn_parse_ContentObject(ndnr->policy_link_cob->buf, ndnr->policy_link_cob->length, &pco, nc); res = ndn_ref_tagged_BLOB(NDN_DTAG_Content, ndnr->policy_link_cob->buf, pco.offset[NDN_PCO_B_Content], pco.offset[NDN_PCO_E_Content], &buf, &length); d = ndn_buf_decoder_start(&decoder, buf, length); res = ndn_parse_Link(d, &pl, NULL); if (res <= 0) { ndnr_msg(ndnr, "Policy link is malformed."); goto CreateNewPolicy; } basename = ndn_charbuf_create(); ndn_charbuf_append(basename, buf + pl.offset[NDN_PL_B_Name], pl.offset[NDN_PL_E_Name] - pl.offset[NDN_PL_B_Name]); ndnr->policy_name = ndn_charbuf_create(); // to detect writes to this name ndn_charbuf_append_charbuf(ndnr->policy_name, basename); // has version ndn_name_chop(ndnr->policy_name, NULL, -1); // get rid of version policy = ndn_charbuf_create(); // if we fail to retrieve the link target, report and then create a new one do { ndn_name_append_numeric(basename, NDN_MARKER_SEQNUM, segment++); content = r_store_lookup_ndnb(ndnr, basename->buf, basename->length); if (content == NULL) { ndnr_debug_ndnb(ndnr, __LINE__, "policy lookup failed for", NULL, basename->buf, basename->length); break; } ndn_name_chop(basename, NULL, -1); content_msg = r_store_content_base(ndnr, content); if (content_msg == NULL) { ndnr_debug_ndnb(ndnr, __LINE__, "Unable to read policy object", NULL, basename->buf, basename->length); break; } res = ndn_parse_ContentObject(content_msg, r_store_content_size(ndnr, content), &pco, nc); res = ndn_ref_tagged_BLOB(NDN_DTAG_Content, content_msg, pco.offset[NDN_PCO_B_Content], pco.offset[NDN_PCO_E_Content], &buf, &length); ndn_charbuf_append(policy, buf, length); final = ndn_is_final_pco(content_msg, &pco, nc); } while (!final && segment < 100);
int ndn_verify_signature(const unsigned char *msg, size_t size, const struct ndn_parsed_ContentObject *co, const struct ndn_pkey *verification_pubkey) { EVP_MD_CTX verc; EVP_MD_CTX *ver_ctx = &verc; X509_SIG *digest_info = NULL; const unsigned char *dd = NULL; MP_info *merkle_path_info = NULL; unsigned char *root_hash = NULL; size_t root_hash_size; int res; const EVP_MD *digest = NULL; const EVP_MD *merkle_path_digest = NULL; const unsigned char *signature_bits = NULL; size_t signature_bits_size = 0; const unsigned char *witness = NULL; size_t witness_size = 0; const unsigned char *digest_algorithm = NULL; size_t digest_algorithm_size; EVP_PKEY *pkey = (EVP_PKEY *)verification_pubkey; res = ndn_ref_tagged_BLOB(NDN_DTAG_SignatureBits, msg, co->offset[NDN_PCO_B_SignatureBits], co->offset[NDN_PCO_E_SignatureBits], &signature_bits, &signature_bits_size); if (res < 0) return (-1); if (co->offset[NDN_PCO_B_DigestAlgorithm] == co->offset[NDN_PCO_E_DigestAlgorithm]) { digest_algorithm = (const unsigned char *)NDN_SIGNING_DEFAULT_DIGEST_ALGORITHM; } else { /* figure out what algorithm the OID represents */ res = ndn_ref_tagged_string(NDN_DTAG_DigestAlgorithm, msg, co->offset[NDN_PCO_B_DigestAlgorithm], co->offset[NDN_PCO_E_DigestAlgorithm], &digest_algorithm, &digest_algorithm_size); if (res < 0) return (-1); /* NOTE: since the element closer is a 0, and the element is well formed, * the string will be null terminated */ } digest = md_from_digest_and_pkey((const char *)digest_algorithm, verification_pubkey); EVP_MD_CTX_init(ver_ctx); res = EVP_VerifyInit_ex(ver_ctx, digest, NULL); if (!res) { EVP_MD_CTX_cleanup(ver_ctx); return (-1); } if (co->offset[NDN_PCO_B_Witness] != co->offset[NDN_PCO_E_Witness]) { /* The witness is a DigestInfo, where the octet-string therein encapsulates * a sequence of [integer (origin 1 node#), sequence of [octet-string]] * where the inner octet-string is the concatenated hashes on the merkle-path */ res = ndn_ref_tagged_BLOB(NDN_DTAG_Witness, msg, co->offset[NDN_PCO_B_Witness], co->offset[NDN_PCO_E_Witness], &witness, &witness_size); if (res < 0) { EVP_MD_CTX_cleanup(ver_ctx); return (-1); } digest_info = d2i_X509_SIG(NULL, &witness, witness_size); /* digest_info->algor->algorithm->{length, data} * digest_info->digest->{length, type, data} */ /* ...2.2 is an MHT w/ SHA256 */ ASN1_OBJECT *merkle_hash_tree_oid = OBJ_txt2obj("1.2.840.113550.11.1.2.2", 1); if (0 != OBJ_cmp(digest_info->algor->algorithm, merkle_hash_tree_oid)) { fprintf(stderr, "A witness is present without an MHT OID!\n"); EVP_MD_CTX_cleanup(ver_ctx); ASN1_OBJECT_free(merkle_hash_tree_oid); return (-1); } /* we're doing an MHT */ ASN1_OBJECT_free(merkle_hash_tree_oid); merkle_path_digest = EVP_sha256(); /* DER-encoded in the digest_info's digest ASN.1 octet string is the Merkle path info */ dd = digest_info->digest->data; merkle_path_info = d2i_MP_info(NULL, &dd, digest_info->digest->length); X509_SIG_free(digest_info); #ifdef DEBUG int x,h; int node = ASN1_INTEGER_get(merkle_path_info->node); int hash_count = sk_ASN1_OCTET_STRING_num(merkle_path_info->hashes); ASN1_OCTET_STRING *hash; fprintf(stderr, "A witness is present with an MHT OID\n"); fprintf(stderr, "This is node %d, with %d hashes\n", node, hash_count); for (h = 0; h < hash_count; h++) { hash = sk_ASN1_OCTET_STRING_value(merkle_path_info->hashes, h); fprintf(stderr, " hashes[%d] len = %d data = ", h, hash->length); for (x = 0; x < hash->length; x++) { fprintf(stderr, "%02x", hash->data[x]); } fprintf(stderr, "\n"); } #endif /* In the MHT signature case, we signed/verify the root hash */ root_hash_size = EVP_MD_size(merkle_path_digest); root_hash = calloc(1, root_hash_size); res = ndn_merkle_root_hash(msg, size, co, merkle_path_digest, merkle_path_info, root_hash, root_hash_size); MP_info_free(merkle_path_info); if (res < 0) { EVP_MD_CTX_cleanup(ver_ctx); free(root_hash); return(-1); } res = EVP_VerifyUpdate(ver_ctx, root_hash, root_hash_size); free(root_hash); if (res == 0) { EVP_MD_CTX_cleanup(ver_ctx); return(-1); } res = EVP_VerifyFinal(ver_ctx, signature_bits, signature_bits_size, pkey); EVP_MD_CTX_cleanup(ver_ctx); } else { /* * In the simple signature case, we signed/verify from the name through * the end of the content. */ size_t signed_size = co->offset[NDN_PCO_E_Content] - co->offset[NDN_PCO_B_Name]; res = EVP_VerifyUpdate(ver_ctx, msg + co->offset[NDN_PCO_B_Name], signed_size); if (res == 0) { EVP_MD_CTX_cleanup(ver_ctx); return(-1); } res = EVP_VerifyFinal(ver_ctx, signature_bits, signature_bits_size, pkey); EVP_MD_CTX_cleanup(ver_ctx); } return (res); }
/** * Handle the incoming content messages. Extracts the data, and * requests the next block in sequence if the received block was * not the final one. */ enum ndn_upcall_res incoming_content(struct ndn_closure *selfp, enum ndn_upcall_kind kind, struct ndn_upcall_info *info) { struct ndn_charbuf *name = NULL; struct ndn_charbuf *templ = NULL; const unsigned char *ndnb = NULL; size_t ndnb_size = 0; const unsigned char *data = NULL; size_t data_size = 0; size_t written; const unsigned char *ib = NULL; /* info->interest_ndnb */ struct ndn_indexbuf *ic = NULL; int res; struct mydata *md = selfp->data; if (kind == NDN_UPCALL_FINAL) { if (md != NULL) { selfp->data = NULL; free(md); md = NULL; } return(NDN_UPCALL_RESULT_OK); } if (kind == NDN_UPCALL_INTEREST_TIMED_OUT) return(NDN_UPCALL_RESULT_REEXPRESS); if (kind == NDN_UPCALL_CONTENT_UNVERIFIED) return(NDN_UPCALL_RESULT_VERIFY); if (kind != NDN_UPCALL_CONTENT) return(NDN_UPCALL_RESULT_ERR); if (md == NULL) selfp->data = md = calloc(1, sizeof(*md)); ndnb = info->content_ndnb; ndnb_size = info->pco->offset[NDN_PCO_E]; ib = info->interest_ndnb; ic = info->interest_comps; res = ndn_content_get_value(ndnb, ndnb_size, info->pco, &data, &data_size); if (res < 0) abort(); if (info->pco->type != NDN_CONTENT_DATA) { /* For us this is spam. For now, give up. */ fprintf(stderr, "*** spammed at block %d\n", (int)selfp->intdata); exit(1); } /* OK, we will accept this block. */ if (data_size == 0) *(md->done) = 1; else { written = fwrite(data, data_size, 1, stdout); if (written != 1) exit(1); } // XXX The test below should get refactored into the library if (info->pco->offset[NDN_PCO_B_FinalBlockID] != info->pco->offset[NDN_PCO_E_FinalBlockID]) { const unsigned char *finalid = NULL; size_t finalid_size = 0; const unsigned char *nameid = NULL; size_t nameid_size = 0; struct ndn_indexbuf *cc = info->content_comps; ndn_ref_tagged_BLOB(NDN_DTAG_FinalBlockID, ndnb, info->pco->offset[NDN_PCO_B_FinalBlockID], info->pco->offset[NDN_PCO_E_FinalBlockID], &finalid, &finalid_size); if (cc->n < 2) abort(); ndn_ref_tagged_BLOB(NDN_DTAG_Component, ndnb, cc->buf[cc->n - 2], cc->buf[cc->n - 1], &nameid, &nameid_size); if (finalid_size == nameid_size && 0 == memcmp(finalid, nameid, nameid_size)) *(md->done) = 1; } if (*(md->done)) { ndn_set_run_timeout(info->h, 0); return(NDN_UPCALL_RESULT_OK); } /* Ask for the next fragment */ name = ndn_charbuf_create(); ndn_name_init(name); if (ic->n < 2) abort(); res = ndn_name_append_components(name, ib, ic->buf[0], ic->buf[ic->n - 2]); if (res < 0) abort(); ndn_name_append_numeric(name, NDN_MARKER_SEQNUM, ++(selfp->intdata)); templ = make_template(md, info); res = ndn_express_interest(info->h, name, selfp, templ); if (res < 0) abort(); ndn_charbuf_destroy(&templ); ndn_charbuf_destroy(&name); return(NDN_UPCALL_RESULT_OK); }