Пример #1
0
/**
 *
 * Create new face by sending out a request Interest
 * The actual new face instance is returned
 * 
 */
static 
struct ccn_face_instance *create_face(struct ccn *h, struct ccn_charbuf *local_scope_template,
        struct ccn_charbuf *no_name, struct ccn_face_instance *face_instance)
{
	struct ccn_charbuf *newface = NULL;
	struct ccn_charbuf *signed_info = NULL;
	struct ccn_charbuf *temp = NULL;
	struct ccn_charbuf *name = NULL;
	struct ccn_charbuf *resultbuf = NULL;
	struct ccn_parsed_ContentObject pcobuf = {0};
	struct ccn_face_instance *new_face_instance = NULL;
	const unsigned char *ptr = NULL;
	size_t length = 0;
	int res = 0;

	/* Encode the given face instance */
	newface = ccn_charbuf_create();
	ccnb_append_face_instance(newface, face_instance);

	temp = ccn_charbuf_create();
	res = ccn_sign_content(h, temp, no_name, NULL, newface->buf, newface->length);
	resultbuf = ccn_charbuf_create();

	/* Construct the Interest name that will create the face */
	name = ccn_charbuf_create();
	ccn_name_init(name);
	ccn_name_append_str(name, "ccnx");
	ccn_name_append(name, face_instance->ccnd_id, face_instance->ccnd_id_size);
	ccn_name_append_str(name, face_instance->action);
	ccn_name_append(name, temp->buf, temp->length);

	/* send Interest to retrieve Data that contains the newly created face */
	res = ccn_get(h, name, local_scope_template, 1000, resultbuf, &pcobuf, NULL, 0);
	ON_ERROR_CLEANUP(res);

	/* decode Data to get the actual face instance */
	res = ccn_content_get_value(resultbuf->buf, resultbuf->length, &pcobuf, &ptr, &length);
	ON_ERROR_CLEANUP(res);

	new_face_instance = ccn_face_instance_parse(ptr, length);

	ccn_charbuf_destroy(&newface);
	ccn_charbuf_destroy(&signed_info);
	ccn_charbuf_destroy(&temp);
	ccn_charbuf_destroy(&resultbuf);
	ccn_charbuf_destroy(&name);

	return new_face_instance;

	cleanup:
		ccn_charbuf_destroy(&newface);
		ccn_charbuf_destroy(&signed_info);
		ccn_charbuf_destroy(&temp);
		ccn_charbuf_destroy(&resultbuf);
		ccn_charbuf_destroy(&name);

	return NULL;
}
Пример #2
0
void CcnCC_sendContent(CcnCC self, struct ccn_charbuf* name, TimeSpan expires, void* data, size_t size) {
	struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT;
	if (expires >= 0) {
		sp.template_ccnb = ccn_charbuf_create();
		ccn_charbuf_append_tt(sp.template_ccnb, CCN_DTAG_SignedInfo, CCN_DTAG);
		ccnb_tagged_putf(sp.template_ccnb, CCN_DTAG_FreshnessSeconds, "%ld", expires / 1000);
		sp.sp_flags |= CCN_SP_TEMPL_FRESHNESS;
		ccn_charbuf_append_closer(sp.template_ccnb);
	}
	struct ccn_charbuf* content = ccn_charbuf_create();
	if (0 == ccn_sign_content(self->ccnh, content, name, &sp, data, size)) {
		ccn_put(self->ccnh, content->buf, content->length);
	}
	ccn_charbuf_destroy(&sp.template_ccnb);
	ccn_charbuf_destroy(&content);
}
Пример #3
0
/**
 * should probably return a new cob, rather than reusing one.
 * should publish link as:
 *    CCNRID_POLICY_URI("ccnx:/%C1.M.S.localhost/%C1.M.SRV/repository/POLICY)/%C1.M.K--pubid--/--version--/%00
 * should have key locator which is the key name of the repository
 */
PUBLIC struct ccn_charbuf *
ccnr_init_policy_link_cob(struct ccnr_handle *ccnr, struct ccn *h,
                          struct ccn_charbuf *targetname)
{
    struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT;
    struct ccn_charbuf *name = ccn_charbuf_create();
    struct ccn_charbuf *pubid = ccn_charbuf_create();
    struct ccn_charbuf *pubkey = ccn_charbuf_create();
    struct ccn_charbuf *keyid = ccn_charbuf_create();
    struct ccn_charbuf *content = ccn_charbuf_create();
    struct ccn_charbuf *cob = ccn_charbuf_create();
    struct ccn_charbuf *answer = NULL;
    int res;
    
    res = ccn_get_public_key(h, NULL, pubid, pubkey);
    if (res < 0)
        goto Bail;
    if (ccn_name_from_uri(name, CCNRID_POLICY_URI) < 0)
        goto Bail;
    res |= ccn_charbuf_append_value(keyid, CCN_MARKER_CONTROL, 1);
    res |= ccn_charbuf_append_string(keyid, ".M.K");
    res |= ccn_charbuf_append_value(keyid, 0, 1);
    res |= ccn_charbuf_append_charbuf(keyid, pubid);
    res |= ccn_name_append(name, keyid->buf, keyid->length);
    res |= ccn_create_version(h, name, CCN_V_NOW, 0, 0);
    if (ccn_name_from_uri(name, "%00") < 0)
        goto Bail;
    sp.sp_flags |= CCN_SP_FINAL_BLOCK;
    sp.type = CCN_CONTENT_LINK;
    res |= ccnb_append_Link(content, targetname, "Repository Policy", NULL);
    if (res != 0)
        goto Bail;
    res |= ccn_sign_content(h, cob, name, &sp, content->buf, content->length);
    if (res != 0)
        goto Bail;
    answer = cob;
    cob = NULL;
    
Bail:
    ccn_charbuf_destroy(&name);
    ccn_charbuf_destroy(&pubid);
    ccn_charbuf_destroy(&pubkey);
    ccn_charbuf_destroy(&keyid);
    ccn_charbuf_destroy(&content);
    ccn_charbuf_destroy(&cob);
    return (answer);
}
Пример #4
0
enum ccn_upcall_res
ccn_proxy_server_decap_interest(
    struct ccn_closure *selfp,
    enum ccn_upcall_kind kind,
    struct ccn_upcall_info *info)
{
    enum ccn_upcall_res upcall_res = CCN_UPCALL_RESULT_ERR;
    struct ccn_proxy_server* server = selfp->data;
    struct ccn_proxy* proxy = server->proxy;
    // struct ccn_proxy *proxy = (selfp->data)->proxy;
    int i, res;
    unsigned char* random = NULL;
    struct ccn_charbuf* request_name;
    struct ccn_indexbuf* request_comps;
    struct ccn_charbuf* signed_info;
    struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT;

    random = (unsigned char*)malloc(RESP_SIZE * sizeof(unsigned char));
    for (i = 0; i < RESP_SIZE; i++) random[i] = rand() % 256;

    handled++;
    printf("random buffer created - creating signed object: %d\n", handled);

    // Create a valid, signed ContentObject
    request_name = NULL;
    request_comps = NULL;
    res = ccn_util_extract_name(info->interest_ccnb, info->interest_comps, &request_name, &request_comps);
    signed_info = ccn_charbuf_create();
    sp.type = CCN_CONTENT_DATA;
    res = ccn_sign_content(proxy->handle, signed_info, request_name, &sp, random, RESP_SIZE);

    // Drop the content object into the socket (handle) to be sent back downstream
    res = ccn_put(proxy->handle, signed_info->buf, signed_info->length);
    if (res < 0)
    {
        ccn_perror(proxy->handle, NULL);
        printf("WTF?!?!?!\n");
    }
    else
    {
        printf("successfully put content object in the socket\n");
    }

    // // TODO: need to fill up random buffer and then inject it using ccn_put

    return(CCN_UPCALL_RESULT_OK);
}
Пример #5
0
static struct ccn_charbuf *
ccnr_init_service_ccnb(struct ccnr_handle *ccnr, struct ccn *h, const char *baseuri, int freshness)
{
    struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT;
    struct ccn_charbuf *name = ccn_charbuf_create();
    struct ccn_charbuf *pubid = ccn_charbuf_create();
    struct ccn_charbuf *pubkey = ccn_charbuf_create();
    struct ccn_charbuf *keyid = ccn_charbuf_create();
    struct ccn_charbuf *cob = ccn_charbuf_create();
    int res;
    
    res = ccn_get_public_key(h, NULL, pubid, pubkey);
    if (res < 0) abort();
    ccn_name_from_uri(name, baseuri);
    ccn_charbuf_append_value(keyid, CCN_MARKER_CONTROL, 1);
    ccn_charbuf_append_string(keyid, ".M.K");
    ccn_charbuf_append_value(keyid, 0, 1);
    ccn_charbuf_append_charbuf(keyid, pubid);
    ccn_name_append(name, keyid->buf, keyid->length);
    ccn_create_version(h, name, 0, ccnr->starttime, ccnr->starttime_usec * 1000);
    sp.template_ccnb = ccn_charbuf_create();
    ccnb_element_begin(sp.template_ccnb, CCN_DTAG_SignedInfo);
    ccnb_element_begin(sp.template_ccnb, CCN_DTAG_KeyLocator);
    ccnb_element_begin(sp.template_ccnb, CCN_DTAG_KeyName);
    ccn_charbuf_append_charbuf(sp.template_ccnb, name);
    ccnb_element_end(sp.template_ccnb);
//    ccn_charbuf_append_tt(sp.template_ccnb, CCN_DTAG_PublisherPublicKeyDigest,
//                          CCN_DTAG);
//    ccn_charbuf_append_charbuf(sp.template_ccnb, pubid);
//    ccnb_element_end(sp.template_ccnb);
    ccnb_element_end(sp.template_ccnb);
    ccnb_element_end(sp.template_ccnb);
    sp.sp_flags |= CCN_SP_TEMPL_KEY_LOCATOR;
    ccn_name_from_uri(name, "%00");
    sp.sp_flags |= CCN_SP_FINAL_BLOCK;
    sp.type = CCN_CONTENT_KEY;
    sp.freshness = freshness;
    res = ccn_sign_content(h, cob, name, &sp, pubkey->buf, pubkey->length);
    if (res != 0) abort();
    ccn_charbuf_destroy(&name);
    ccn_charbuf_destroy(&pubid);
    ccn_charbuf_destroy(&pubkey);
    ccn_charbuf_destroy(&keyid);
    ccn_charbuf_destroy(&sp.template_ccnb);
    return(cob);
}
Пример #6
0
static struct ccn_charbuf *
seqw_next_cob(struct ccn_seqwriter *w)
{
    struct ccn_charbuf *cob = ccn_charbuf_create();
    struct ccn_charbuf *name = ccn_charbuf_create();
    struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT;
    int res;
    
    if (w->closed)
        sp.sp_flags |= CCN_SP_FINAL_BLOCK;
    ccn_charbuf_append(name, w->nv->buf, w->nv->length);
    ccn_name_append_numeric(name, CCN_MARKER_SEQNUM, w->seqnum);
    res = ccn_sign_content(w->h, cob, name, &sp, w->buffer->buf, w->buffer->length);
    if (res < 0)
        ccn_charbuf_destroy(&cob);
    ccn_charbuf_destroy(&name);
    return(cob);
}
Пример #7
0
struct ccn_charbuf* CcnH_signForwardingEntry(struct ccn* ccnh, CCNDID ccndid, struct ccn_forwarding_entry* fe) {
	struct ccn_charbuf* request = ccn_charbuf_create();
	ccnb_append_forwarding_entry(request, fe);
	struct ccn_charbuf* emptyname = ccn_charbuf_create();
	ccn_name_init(emptyname);
	struct ccn_charbuf* signed_request = ccn_charbuf_create();
	ccn_sign_content(ccnh, signed_request, emptyname, NULL, request->buf, request->length);

	struct ccn_charbuf* reqname = ccn_charbuf_create();
	ccn_name_from_uri(reqname, "ccnx:/ccnx");
	ccn_name_append(reqname, ccndid, CCNDID_length);
	ccn_name_append_str(reqname, fe->action);
	ccn_name_append(reqname, signed_request->buf, signed_request->length);

	ccn_charbuf_destroy(&request);
	ccn_charbuf_destroy(&emptyname);
	ccn_charbuf_destroy(&signed_request);
	return reqname;
}
Пример #8
0
static struct ccn_charbuf *
ccnr_init_policy_cob(struct ccnr_handle *ccnr, struct ccn *h,
                     struct ccn_charbuf *basename,
                     int freshness, struct ccn_charbuf *content)
{
    struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT;
    struct ccn_charbuf *name = ccn_charbuf_create();
    struct ccn_charbuf *pubid = ccn_charbuf_create();
    struct ccn_charbuf *pubkey = ccn_charbuf_create();
    struct ccn_charbuf *keyid = ccn_charbuf_create();
    struct ccn_charbuf *tcob = ccn_charbuf_create();
    struct ccn_charbuf *cob = NULL;          // result
    int res;
    
    res = ccn_get_public_key(h, NULL, pubid, pubkey);
    if (res < 0) 
        goto Leave;
    res = ccn_charbuf_append_charbuf(name, basename);
    if (ccn_name_from_uri(name, "%00") < 0)
        goto Leave;
    sp.sp_flags |= CCN_SP_FINAL_BLOCK;
    sp.type = CCN_CONTENT_DATA;
    sp.freshness = freshness;
    res |= ccn_sign_content(h, tcob, name, &sp, content->buf, content->length);
    if (res == 0) {
        cob = tcob;
        tcob = NULL;
    }
    
Leave:
    ccn_charbuf_destroy(&name);
    ccn_charbuf_destroy(&pubid);
    ccn_charbuf_destroy(&pubkey);
    ccn_charbuf_destroy(&keyid);
    ccn_charbuf_destroy(&tcob);
    return (cob);
}
Пример #9
0
int main(void) {
	int res;
	struct ccn *ccn= NULL;
	struct ccn_charbuf *name = NULL;
	struct ccn_charbuf *result = NULL;
	struct ccn_closure in_interest = {.p=&incoming_interest};
	struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT; // Parameters for creating signed content objects.
	char rawcontentbuf[1024] = "";
	size_t content_size;

	// 1. Name
	name = ccn_charbuf_create();
	res = ccn_name_from_uri(name, URI);
	if (res < 0) {
		fprintf(stderr, "bad ccn URI: %s\n", URI);
		exit(1);
	}

	// 2. ccn_create, and ccn_connect
	ccn = ccn_create();
	res = ccn_connect(ccn, NULL);
	if (res < 0) {
		fprintf(stderr, "can't connect to ccnd: %d\n", res);
		ccn_perror(ccn, "ccn_connect");
		exit(1);
	}

	// 3. Create the signed content object, set up &sp - signing params;

	// Extend a Name with a new version stamp if requested
	/*int versioned = 0;
	const char *postver = NULL;
	memcmp(postver, "%00", 3);
	if (versioned) {
		res = ccn_create_version(ccn, name, CCN_V_REPLACE | CCN_V_NOW | CCN_V_HIGH, 0, 0);
		if (res < 0) {
			fprintf(stderr, "%s: ccn_create_version() failed\n");
			exit(1);
		}
		if (postver != NULL) {
			res = ccn_name_from_uri(name, postver);
			if (res < 0) {
				fprintf(stderr, "-V %s: invalid name suffix\n", postver);
				exit(0);
			}
		}
	} */

	// Ask for a FinalBlockID if appropriate
	/*int setfinal = 0;
	if (setfinal)
		sp.sp_flags |= CCN_SP_FINAL_BLOCK;
	*/

	// Set content type
	//sp.type = content_type;

	// Set freshness
	/* The template_ccnb may contain a ccnb-encoded SignedInfo to supply selected fields from under
	 * the direction of sp_flags.
	 */
	/*int expire = -1;
	if (expire >= 0) {
		if (sp.template_ccnb == NULL) {
			sp.template_ccnb = ccn_charbuf_create();
			ccn_charbuf_append_tt(sp.template_ccnb, CCN_DTAG_SignedInfo, CCN_DTAG);
			}
		else if (sp.template_ccnb -> length > 0) {
			sp.template_ccnb -> length--;
		}
		ccnb_tagged_putf(sp.template_ccnb, CCN_DTAG_FreshnessSeconds, "%ld", expire);
		sp.sp_flags |= CCN_SP_TEMPL_FRESHNESS;
		ccn_charbuf_append_closer(sp.template_ccnb);
	}
	*/

	// Set key locator, if supplied
	/*const char *key_uri = NULL;
	//key_uri = optarg;
	if (key_uri != NULL) {
		struct ccn_charbuf *c = ccn_charbuf_create();
		res = ccn_name_from_uri(c, key_uri);
		if (res < 0) {
			fprintf(stderr, "%s is not a valid ccnx URI\n", key_uri);
			exit(1);
		}
		if (sp.template_ccnb == NULL) {
			sp.template_ccnb = ccn_charbuf_create();
			ccn_charbuf_append_tt(sp.template_ccnb, CCN_DTAG_SignedInfo, CCN_DTAG);
		}
		else if (sp.template_ccnb -> length > 0) {
			sp.template_ccnb -> length--;
		}
		ccn_charbuf_append_tt(sp.template_ccnb, CCN_DTAG_KeyLocator, CCN_DTAG);
		ccn_charbuf_append_tt(sp.template_ccnb, CCN_DTAG_KeyName, CCN_DTAG);
		ccn_charbuf_append(sp.template_ccnb, c->buf, c->length);
		ccn_charbuf_append_closer(sp.template_ccnb);
		ccn_charbuf_append_closer(sp.template_ccnb);
		sp.sp_flags |= CCN_SP_TEMPL_KEY_LOCATOR;
		ccn_charbuf_append_closer(sp.template_ccnb);
		ccn_charbuf_destroy(&c);
	}
	*/

	// Set up a handler for interest
	ccn_set_interest_filter(ccn, name, &in_interest);


	// 4. Use ccn_sign_content to create the signed content object with composed &sp,
	// if (force) { ccn_put; } # ccn_get means send ccn binary. For normal clients, this should be a ContentObject sent in response to an Interest.
	// else { ccn_set_interest_filter; ccn_run; }

	result = ccn_charbuf_create();
	result -> length = 0;
	strcat(rawcontentbuf, CONTENTDATA);
	content_size = strlen(rawcontentbuf);
	//sp.sp_flags |= CCN_SP_FINAL_BLOCK;
	res = ccn_sign_content(ccn, result, name, &sp, rawcontentbuf, content_size);
	if (res < 0) {
		ccn_perror(ccn, "ccn_sign_content");
		exit(1);
	}

	printf("Content signed, trying to send the data...\n");
	res = ccn_put(ccn, result->buf, result->length);
	if (res < 0) {
		ccn_perror(ccn, "ccn_put");
		printf("Failed to send content object: res = %d\n", res);
		exit(1);
	}
	else
		printf("ccn_put done, content object sent.\n");

	// ccn_run serves as the event loop when timeout = -1
	res = ccn_run(ccn, -1);  // Loop here all the time until it is killed, then "Event loop..."
	printf("Event loop...\n");
	if (res < 0) {
		ccn_perror(ccn, "ccn_run");
		printf("Error: ccn_run\n");
		exit(1);
	}

	ccn_destroy(&ccn);
	ccn_charbuf_destroy(&name);
	ccn_charbuf_destroy(&result);
	ccn_charbuf_destroy(&sp.template_ccnb);
	printf("ccn handle is destroyed... \n");

	return 0;

}
Пример #10
0
/**
 * 
 * Bind a prefix to a face
 *
 */
static int 
register_unregister_prefix(struct ccn *h, struct ccn_charbuf *local_scope_template,
        struct ccn_charbuf *no_name, struct ccn_charbuf *name_prefix,
        struct ccn_face_instance *face_instance, int operation)
{
	struct ccn_charbuf *temp = NULL;
	struct ccn_charbuf *resultbuf = NULL;
	struct ccn_charbuf *signed_info = NULL;
	struct ccn_charbuf *name = NULL;
	struct ccn_charbuf *prefixreg = NULL;
	struct ccn_parsed_ContentObject pcobuf = {0};
	struct ccn_forwarding_entry forwarding_entry_storage = {0};
	struct ccn_forwarding_entry *forwarding_entry = &forwarding_entry_storage;
	struct ccn_forwarding_entry *new_forwarding_entry;
	const unsigned char *ptr = NULL;
	size_t length = 0;
	int res;

	/* Register or unregister the prefix */
	forwarding_entry->action = (operation == OP_REG) ? "prefixreg" : "unreg";
	forwarding_entry->name_prefix = name_prefix;
	forwarding_entry->ccnd_id = face_instance->ccnd_id;
	forwarding_entry->ccnd_id_size = face_instance->ccnd_id_size;
	forwarding_entry->faceid = face_instance->faceid;
	forwarding_entry->flags = -1;
	forwarding_entry->lifetime = 2100;

	prefixreg = ccn_charbuf_create();
	ccnb_append_forwarding_entry(prefixreg, forwarding_entry);
	temp = ccn_charbuf_create();
	res = ccn_sign_content(h, temp, no_name, NULL, prefixreg->buf, prefixreg->length);
	resultbuf = ccn_charbuf_create();

	/* construct Interest containing prefixreg request */
	name = ccn_charbuf_create();
	ccn_name_init(name);
	ccn_name_append_str(name, "ccnx");
	ccn_name_append(name, face_instance->ccnd_id, face_instance->ccnd_id_size);
	ccn_name_append_str(name, (operation == OP_REG) ? "prefixreg" : "unreg");
	ccn_name_append(name, temp->buf, temp->length);

	/* send Interest, get Data */
	res = ccn_get(h, name, local_scope_template, 1000, resultbuf, &pcobuf, NULL, 0);
	ON_ERROR_CLEANUP(res);

	res = ccn_content_get_value(resultbuf->buf, resultbuf->length, &pcobuf, &ptr, &length);
	ON_ERROR_CLEANUP(res);
    
	/* extract new forwarding entry from Data */
	new_forwarding_entry = ccn_forwarding_entry_parse(ptr, length);
	ON_NULL_CLEANUP(new_forwarding_entry);

	res = new_forwarding_entry->faceid;

	ccn_forwarding_entry_destroy(&new_forwarding_entry);
	ccn_charbuf_destroy(&signed_info);
	ccn_charbuf_destroy(&temp);
	ccn_charbuf_destroy(&resultbuf);
	ccn_charbuf_destroy(&name);
	ccn_charbuf_destroy(&prefixreg);

	return res;

	cleanup:
		ccn_forwarding_entry_destroy(&new_forwarding_entry);
		ccn_charbuf_destroy(&signed_info);
		ccn_charbuf_destroy(&temp);
		ccn_charbuf_destroy(&resultbuf);
		ccn_charbuf_destroy(&name);
		ccn_charbuf_destroy(&prefixreg);

	return -1;
}
Пример #11
0
enum ccn_upcall_res
andana_server_session_listener(
    struct ccn_closure *selfp,
    enum ccn_upcall_kind kind,
    struct ccn_upcall_info *info)
{
    int res;
    struct andana_server *server = selfp->data;

    const unsigned char * const_encrypted = NULL;
    unsigned char *encrypted = NULL;
    size_t enc_size;

    /*
     * Extract the client's randomness (aka the symmetric key it sent us.
     * Should be the last component of the incoming Interest.
     */

    struct ccn_charbuf *request_name = NULL;
    struct ccn_indexbuf *request_comps = NULL;


    DEBUG_PRINT("IN %d %s\n", __LINE__, __func__);

    switch (kind) {
    case CCN_UPCALL_INTEREST:
        DEBUG_PRINT("%d %s received session request\n", __LINE__, __func__);
        break;
    case CCN_UPCALL_INTEREST_TIMED_OUT:
        DEBUG_PRINT("%d %s received session request time out\n", __LINE__, __func__);
        /* Fall through */
    default:
        DEBUG_PRINT("OUT %d %s\n", __LINE__, __func__);
        return(CCN_UPCALL_RESULT_OK);
    }

    printf("here now mk?\n");

    res = ccn_util_extract_name(info->interest_ccnb, info->interest_comps, &request_name, &request_comps);

    if (res < 0) {
        DEBUG_PRINT("%d %s Failed to extract session request name\n", __LINE__, __func__);
        ccn_charbuf_destroy(&request_name);
        ccn_indexbuf_destroy(&request_comps);
        return(CCN_UPCALL_RESULT_ERR);
    }

    printf("passed util extract name\n");

    res = ccn_name_comp_get(request_name->buf,
                            request_comps,
                            (unsigned int)request_comps->n - 2,
                            &const_encrypted,
                            &enc_size);

    if (res < 0) {
        DEBUG_PRINT("%d %s Failed to extract session creation data\n", __LINE__, __func__);
        ccn_charbuf_destroy(&request_name);
        ccn_indexbuf_destroy(&request_comps);
        return(CCN_UPCALL_RESULT_ERR);
    }


    encrypted = calloc(enc_size, sizeof(unsigned char));

    printf("encryption size = %d\n", enc_size);
    if (encrypted == NULL) printf("invalid pointer return from calloc\n");

    memcpy(encrypted, const_encrypted, enc_size);

    struct ccn_pkey *symkey = NULL;
    struct ccn_charbuf *decrypted = NULL;
    struct ccn_indexbuf *decrypted_comps = ccn_indexbuf_create();

    printf("trying asymmetric decryption\n");

    ccn_crypto_name_asym_decrypt(server->privkey, encrypted, &symkey, &decrypted, &decrypted_comps);
    // ccn_crypto_name_sym_decrypt(server->node_key, encrypted, encrypted_size, &decrypted, &decrypted_comps);

    /*
cn_crypto_name_sym_decrypt(server->node_key,
                                    encrypted,
                                    encrypted_size,
                                    &symkey,
                                    &decrypted,
                                    &decrypted_comps);
    */

    printf("good - now creating a session\n");


    unsigned char *session_id = NULL;
    unsigned char *session_key = NULL;
    unsigned char *server_rand = NULL;

    /*
     * Create a new session id and session key using the client's randomness.
     * The server is also responsible for contributing randomness of its own for security.
     */

    createSession(&session_id,
                  &session_key,
                  &server_rand,
                  ccn_crypto_symkey_key(symkey),
                  (unsigned int)ccn_crypto_symkey_bytes(symkey),
                  ccn_crypto_symkey_key(server->node_key));

    printf("Session made!\n");

    /* Construct the response message using a ccn name (for convenience). */

    struct ccn_charbuf *session_info = ccn_charbuf_create();
    ccn_name_init(session_info);
    ccn_name_append(session_info, session_id, SESSIONID_LENGTH);
    ccn_name_append(session_info, session_key, SESSION_KEYLEN);
    ccn_name_append(session_info, server_rand, SESSIONRAND_LENGTH);

    /**
     * Encrypt the response message using the symmetric key
     * provided by the client and send it out.
     */

    unsigned char *enc_info = NULL;
    ccn_crypto_content_encrypt(symkey, session_info->buf, session_info->length, &enc_info, &enc_size);

    struct ccn_charbuf *signed_enc_info = ccn_charbuf_create();
    struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT;
    sp.type = CCN_CONTENT_DATA;


    res = ccn_sign_content(server->proxy->handle,
                           signed_enc_info,
                           request_name,
                           &sp,
                           enc_info,
                           enc_size);

    if (res < 0) {
        DEBUG_PRINT("%d %s Failed to signed session creation response\n", __LINE__, __func__);
    } else {
        res = ccn_put(server->proxy->handle, signed_enc_info->buf, signed_enc_info->length);
    }



    ccn_charbuf_destroy(&decrypted);
    ccn_indexbuf_destroy(&decrypted_comps);
    ccn_crypto_symkey_destroy(&symkey);
    free(session_id);
    free(session_key);
    free(server_rand);
    free(enc_info);
    ccn_charbuf_destroy(&signed_enc_info);

    if (res < 0) {
        DEBUG_PRINT("%d %s Error writing session creation response\n", __LINE__, __func__);
        return(CCN_UPCALL_RESULT_ERR);
    }

    DEBUG_PRINT("OUT %d %s Created new session. Response sent\n", __LINE__, __func__);

    return(CCN_UPCALL_RESULT_INTEREST_CONSUMED);
}
Пример #12
0
/**
 * Call-back from the CCN network that something has arrived
 *
 * We get notified that a client has interests in things we are producing.
 * This function will do some basic checking to see what exactly the client has
 * an interest in, and will produce what is appropriate.
 * Currently the things we produce are:
 * \li last block - we resend the last block we have published for a given name
 * \li last segment - we produce a data message that only contains the latest segment number we used
 *
 * \param	selfp		-> a context structure we created when registering this call-back
 * \param	kind		specifies the type of call-back being processed, see the \b switch statement
 * \param	info		context information about the call-back itself; interests, data, etc.
 * \return a response as to how successful we were in processing the call-back
 * \retval CCN_UPCALL_RESULT_OK		things went well
 * \retval CCN_UPCALL_RESULT_VERIFY	need to verify the contents of what we received
 * \retval CCN_UPCALL_RESULT_REEXPRESS an interest timedout waiting for data, so we try again
 * \retval CCN_UPCALL_RESULT_ERR	some error was encountered
 */
static enum ccn_upcall_res
new_interests (struct ccn_closure *selfp,
    enum ccn_upcall_kind kind, struct ccn_upcall_info *info)
{
  Gstccnxsink *me = GST_CCNXSINK (selfp->data);
  struct ccn_charbuf *cb;
  struct ccn_charbuf *sname = NULL;
  const unsigned char *cp1, *cp2;
  size_t sz1;
  size_t sz2;
  long lastSeq;
  struct ccn_signing_params myparams;
  unsigned int i;
  int rc;


  GST_DEBUG ("something has arrived!");
  GST_DEBUG ("matched is: %d", info->matched_comps);    // number of filter components that were matched by the interest
  cb = interestAsUri (info);
  GST_DEBUG ("as URI: %s", ccn_charbuf_as_string (cb));
  ccn_charbuf_destroy (&cb);

  myparams = me->sp;

  /* Some debugging stuff */
  for (i = 0; i < 10; ++i) {
    const unsigned char *cp;
    size_t sz;
    GST_DEBUG ("%3d: ", i);
    if (0 > ccn_name_comp_get (info->interest_ccnb, info->interest_comps, i,
            &cp, &sz)) {
      // fprintf(stderr, "could not get comp\n");
      break;
    } else {
      // hDump( DUMP_ADDR( cp ), DUMP_SIZE( sz ) );
    }
  }

  switch (kind) {

    case CCN_UPCALL_FINAL:
      GST_LOG_OBJECT (me, "CCN upcall final %p", selfp);
      return (0);

    case CCN_UPCALL_INTEREST_TIMED_OUT:
      if (selfp != me->ccn_closure) {
        GST_LOG_OBJECT (me, "CCN Interest timed out on dead closure %p", selfp);
        return (0);
      }
      GST_LOG_OBJECT (me, "CCN upcall reexpress -- timed out");
      if (me->timeouts > 5) {
        GST_LOG_OBJECT (me, "CCN upcall reexpress -- too many reexpressions");
        return (0);
      }
      me->timeouts++;
      return (CCN_UPCALL_RESULT_REEXPRESS);

    case CCN_UPCALL_CONTENT_UNVERIFIED:
      if (selfp != me->ccn_closure) {
        GST_LOG_OBJECT (me, "CCN unverified content on dead closure %p", selfp);
        return (0);
      }
      return (CCN_UPCALL_RESULT_VERIFY);

    case CCN_UPCALL_CONTENT:
      if (selfp != me->ccn_closure) {
        GST_LOG_OBJECT (me, "CCN content on dead closure %p", selfp);
        return (0);
      }
      break;

    case CCN_UPCALL_CONTENT_BAD:
      GST_LOG_OBJECT (me,
          "Content signature verification failed! Discarding.\n");
      return (CCN_UPCALL_RESULT_ERR);

    case CCN_UPCALL_CONSUMED_INTEREST:
      GST_LOG_OBJECT (me, "Upcall consumed interest\n");
      return (CCN_UPCALL_RESULT_ERR);   /* no data */

      /* Here is the most interesting case...when an interest arrives */
    case CCN_UPCALL_INTEREST:
      GST_INFO ("We got an interest\n");
      myparams.freshness = 1;   /* meta data is old very quickly */

      /* See if any meta information is sought */
      for (i = 0;; ++i) {
        if (0 > ccn_name_comp_get (info->interest_ccnb, info->interest_comps, i,
                &cp1, &sz1)) {
          cp1 = NULL;
          break;
        } else {
          if (!strncmp ((const char *) cp1, "_meta_", 6)) {     // OK, found meta, now which one is needed?
            if (0 > ccn_name_comp_get (info->interest_ccnb,
                    info->interest_comps, i + 1, &cp2, &sz2)) {
              GST_LOG_OBJECT (me,
                  "CCN interest received with invalid meta request");
              cp1 = NULL;
            }
            break;
          }                     // Component not meta, keep looking
        }
      }                         // At this point, i is left pointing at '_meta_' or at the end of component list

      if (cp1) {
        // hDump( DUMP_ADDR(cp1), DUMP_SIZE(sz1) );
        // hDump( DUMP_ADDR(cp2), DUMP_SIZE(sz2) );
        if (strncmp ((const char *) cp2, ".segment", 8))
          goto Exit_Interest;   /* not a match */

        /* publish what segment we are up to in reply to the meta request */
        lastSeq = me->segment - 1;
        GST_INFO ("sending meta data....segment: %d", lastSeq);

        sname = ccn_charbuf_create ();
        ccn_name_init (sname);
        rc = ccn_name_append_components (sname, info->interest_ccnb,
            info->interest_comps->buf[0], info->interest_comps->buf[i + 2]);
        if (rc < 0)
          goto Error_Interest;
        // rc = ccn_create_version(me->ccn, sname, CCN_V_REPLACE | CCN_V_NOW | CCN_V_HIGH, 0, 0);
        // if (rc < 0) goto Error_Interest;
        me->temp->length = 0;
        rc = ccn_sign_content (me->ccn, me->temp, sname, &myparams,
            &lastSeq, sizeof (lastSeq));
        // hDump(DUMP_ADDR(sname->buf), DUMP_SIZE(sname->length));
        if (rc != 0) {
          GST_LOG_OBJECT (me, "Failed to encode ContentObject (rc == %d)\n",
              rc);
          goto Error_Interest;
        }

        GST_INFO ("sending meta data...");
        // hDump(DUMP_ADDR(me->temp->buf), DUMP_SIZE(me->temp->length));
        rc = ccn_put (me->ccn, me->temp->buf, me->temp->length);
        me->temp->length = 0;
        if (rc < 0) {
          GST_LOG_OBJECT (me, "ccn_put failed (res == %d)\n", rc);
          goto Error_Interest;
        }
        GST_INFO ("meta data sent");

      } else
        goto Exit_Interest;     /* do not have _meta_ */

    Exit_Interest:
      ccn_charbuf_destroy (&sname);
      break;

    Error_Interest:
      ccn_charbuf_destroy (&sname);
      return CCN_UPCALL_RESULT_ERR;


    default:
      GST_LOG_OBJECT (me, "CCN upcall result error");
      return (CCN_UPCALL_RESULT_ERR);
  }


  me->timeouts = 0;


  return (CCN_UPCALL_RESULT_OK);

}
Пример #13
0
/**
 * Send out a message onto the CCNx network
 *
 * Once a data buffer is ready to be sent onto the network, there are
 * a few more steps involved in preparing it for thta journey.
 * The CCN stack dictates that all data content messages must contain
 * a proper name, and be signed by the sender.
 * \todo some day we should also encrypt the data; I don't think it is now
 * Much of the information we need to accomplish the message preperation is
 * found in the element context or as one of the parameters.
 *
 * Most of the work is dealing with changing from the internal buffer size and
 * the message size of the CCN network.
 * We chop things up as needed and send each data message out, properly named and signed.
 * The naming will include the timestamp as well as a segment number.
 * If there are some partial bytes left over, that do not fill a CCN message packet,
 * we retain those to be sent out on the next call to this method.
 * The bytes are kept in the element context as is other pertinent information.
 *
 * \param me
 * \param data		pointer to the data buffer to send
 * \param size		number of bytes to send in the message
 * \param ts		timestamp to use on the outbound message
 * \return a GST flow return value indicating the result of our attempt
 * \retval GST_FLOW_OK everything went well
 * \retval GST_FLOW_ERROR something went wrong
 */
static GstFlowReturn
gst_ccnxsink_send (Gstccnxsink * me, guint8 * data, guint size, /*@unused@ */
    GstClockTime ts)
{
  struct ccn_charbuf *sname;    /* where we construct the name of this data message */
  struct ccn_charbuf *hold;     /* holds the last block published so we can properly manage memory */
  struct ccn_charbuf *temp;     /* where we construct the message to send */
  struct ccn_charbuf *signed_info;      /* signing data within the message */
  gint rc;                      /* return status on various calls */
  guint8 *xferStart;            /* points into the source buffer, data, as we packetize into CCN blocks */
  size_t bytesLeft;             /* keeps track of how much more we have to do */

  /* Initialize our local storage and allocate buffers we will need */
  xferStart = data;
  bytesLeft = size;
  sname = ccn_charbuf_create ();
  temp = ccn_charbuf_create ();
  signed_info = ccn_charbuf_create ();

  /* Hang onto this pointer so we can release the buffer as we exit this function */
  hold = me->lastPublish;

/*
 * I am hanging onto this code for now to handle the day when we want to encode the data.
 * I do not know why id did not work during development, but I am sure it is close to working 8-)
 * In the future, feel free to purge this if we never get around to using it.
 * Similarly for the code block that is down below a little bit.
 *
  if( me->keystore ) {
    signed_info->length = 0;
GST_LOG_OBJECT( me, "send - signing info\n" );
    rc = ccn_signed_info_create(signed_info
                                 , ccn_keystore_public_key_digest(me->keystore) //pubkeyid 
                                 , ccn_keystore_public_key_digest_length(me->keystore) //publisher_key_id_size 
                                 , NULL			//datetime
                                 , CCN_CONTENT_DATA	//type
                                 , me->expire		//freshness
                                 , NULL			//finalblockid
                                 , me->keylocator);
    // Put the keylocator in the first block only. 
    ccn_charbuf_destroy(&(me->keylocator));
    if (rc < 0) {
        GST_LOG_OBJECT(me, "Failed to create signed_info (rc == %d)\n", rc);
        goto Trouble;
    }
  }
	*/

  if (me->partial) {            /* We had some left over from the last send */
    size_t extra;
    uintmax_t seg;

    /* find out how much room we have left, and copy over the bytes we have, or need to fill the block */
    extra = CCN_CHUNK_SIZE - me->partial->length;
    if (extra > bytesLeft)
      extra = bytesLeft;
    GST_LOG_OBJECT (me, "send - had a partial left: %d\n", extra);
    ccn_charbuf_append (me->partial, xferStart, extra);

    /* Adjust count and pointer to reflect the bytes we have taken */
    bytesLeft -= extra;
    xferStart += extra;

    /* Filling to the size of the CCN packet means we need to send it out */
    if (me->partial->length == CCN_CHUNK_SIZE) {
      sname->length = 0;
      seg = me->segment++;

      /* build up a name starting with the prefix, then the sequence number */
      ccn_charbuf_append (sname, me->name->buf, me->name->length);
      ccn_name_append_numeric (sname, CCN_MARKER_SEQNUM, seg);
      temp->length = 0;

      /* Signing via this function does a lot of work. The result is a buffer, temp, that is ready to be sent */
      ccn_sign_content (me->ccn, temp, sname, &me->sp, me->partial->buf,
          CCN_CHUNK_SIZE);
      //  hDump( sname->buf, sname->length );
      /*
       * See the comment above about holding this code.
       *
       if( me->keystore ) {

       rc = ccn_encode_ContentObject(temp,
       sname,
       signed_info,
       me->partial->buf,
       CCN_CHUNK_SIZE,
       NULL,
       ccn_keystore_private_key(me->keystore));
       if (rc != 0) {
       GST_LOG_OBJECT( me, "Failed to encode ContentObject (rc == %d)\n", rc);
       goto Trouble;
       }
       */
      /* send the data message on its way */
      rc = ccn_put (me->ccn, temp->buf, temp->length);
      if (rc < 0) {
        GST_LOG_OBJECT (me, "ccn_put failed (rc == %d)\n", rc);
        goto Trouble;
      }
      /* free the buffer we used for the partial data */
      ccn_charbuf_destroy (&me->partial);
      me->partial = NULL;
/*
} else {
		GST_LOG_OBJECT( me, "No keystore. What should we do?\n" );
		goto Trouble;
	  }
*/
    }
  }

  /* No left over means we can send direct out of the data buffer */
  /* Now that we are done with the partial block, go and process the new data in much the same fashion */
  while (bytesLeft >= CCN_CHUNK_SIZE) {
    uintmax_t seg;
    GST_LOG_OBJECT (me, "send - bytesLeft: %d\n", bytesLeft);
    sname->length = 0;
    seg = me->segment++;
    ccn_charbuf_append (sname, me->name->buf, me->name->length);
    ccn_name_append_numeric (sname, CCN_MARKER_SEQNUM, seg);
    GST_LOG_OBJECT (me, "send - name is ready\n");
    temp->length = 0;

    ccn_sign_content (me->ccn, temp, sname, &me->sp, xferStart, CCN_CHUNK_SIZE);
    //  hDump( sname->buf, sname->length );
    /*
       if( me->keystore ) {

       GST_LOG_OBJECT( me, "send - encoding\n" );
       rc = ccn_encode_ContentObject(temp,
       sname,
       signed_info,
       xferStart,
       CCN_CHUNK_SIZE,
       NULL,
       ccn_keystore_private_key(me->keystore));
       if (rc != 0) {
       GST_LOG_OBJECT( me, "Failed to encode ContentObject (rc == %d)\n", rc);
       goto Trouble;
       }
     */
    GST_LOG_OBJECT (me, "send - putting\n");
    rc = ccn_put (me->ccn, temp->buf, temp->length);
    if (rc < 0) {
      GST_LOG_OBJECT (me, "ccn_put failed (rc == %d)\n", rc);
      goto Trouble;
    }
    /*
       } else {
       GST_LOG_OBJECT( me, "No keystore. What should we do?\n" );
       goto Trouble;
       }
     */
    GST_LOG_OBJECT (me, "send - adjusting buffers\n");
    /* msleep(5); */
    bytesLeft -= CCN_CHUNK_SIZE;
    xferStart += CCN_CHUNK_SIZE;
  }                             /* end of while() */

  if (bytesLeft) {              /* We have some left over for next time */
    GST_LOG_OBJECT (me, "send - for next time: %d\n", bytesLeft);
    me->partial = ccn_charbuf_create ();
    me->partial->length = 0;
    ccn_charbuf_append (me->partial, xferStart, bytesLeft);
  }

  /* Do proper memory management, then return */
  ccn_charbuf_destroy (&sname);
  me->lastPublish = temp;
  ccn_charbuf_destroy (&hold);
  ccn_charbuf_destroy (&signed_info);
  GST_LOG_OBJECT (me, "send - leaving length: %d\n", me->lastPublish->length);
  return GST_FLOW_OK;

Trouble:
  ccn_charbuf_destroy (&sname);
  ccn_charbuf_destroy (&temp);
  ccn_charbuf_destroy (&signed_info);
  return GST_FLOW_ERROR;
}
Пример #14
0
int
main(int argc, char **argv)
{
    struct ccn *h = NULL;
    struct ccn_charbuf *name = NULL;
    struct ccn_charbuf *null_name = NULL;
    struct ccn_charbuf *name_prefix = NULL;
    struct ccn_charbuf *newface = NULL;
    struct ccn_charbuf *prefixreg = NULL;
    struct ccn_charbuf *resultbuf = NULL;
    struct ccn_charbuf *temp = NULL;
    struct ccn_charbuf *templ = NULL;
    const unsigned char *ptr = NULL;
    size_t length = 0;
    const char *arg = NULL;
    const char *progname = NULL;
    struct ccn_parsed_ContentObject pcobuf = {0};
    struct ccn_face_instance face_instance_storage = {0};
    struct ccn_face_instance *face_instance = &face_instance_storage;
    struct ccn_forwarding_entry forwarding_entry_storage = {0};
    struct ccn_forwarding_entry *forwarding_entry = &forwarding_entry_storage;
    struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT;
    struct ccn_charbuf *keylocator_templ = NULL;
    struct ccn_keystore *keystore = NULL;
    long expire = -1;
    int ipproto;
    unsigned char ccndid_storage[32] = {0};
    const unsigned char *ccndid = NULL;
    size_t ccndid_size = 0;
    int res;
    int opt;

    progname = argv[0];
    while ((opt = getopt(argc, argv, "h")) != -1) {
        switch (opt) {
        case 'h':
        default:
            usage(progname);
        }
    }

    /* Sanity check the URI and argument count */
    arg = argv[optind];
    if (arg == NULL)
        usage(progname);
    name = ccn_charbuf_create();
    res = ccn_name_from_uri(name, arg);
    if (res < 0) {
        fprintf(stderr, "%s: bad ccn URI: %s\n", progname, arg);
        exit(1);
    }
    if (argc - optind < 3 || argc - optind > 4)
        usage(progname);

    h = ccn_create();
    res = ccn_connect(h, NULL);
    if (res < 0) {
        ccn_perror(h, "ccn_connect");
        exit(1);
    }

    newface = ccn_charbuf_create();
    temp = ccn_charbuf_create();
    templ = ccn_charbuf_create();
    keylocator_templ = ccn_charbuf_create();

    resultbuf = ccn_charbuf_create();
    name_prefix = ccn_charbuf_create();
    null_name = ccn_charbuf_create();
    CHKRES(ccn_name_init(null_name));

    keystore = ccn_keystore_create();

    /* We need to figure out our local ccnd's CCIDID */
    /* Set up our Interest template to indicate scope 1 */
    ccn_charbuf_reset(templ);
    ccnb_element_begin(templ, CCN_DTAG_Interest);
    ccnb_element_begin(templ, CCN_DTAG_Name);
    ccnb_element_end(templ);	/* </Name> */
    ccnb_tagged_putf(templ, CCN_DTAG_Scope, "1");
    ccnb_element_end(templ);	/* </Interest> */

    ccn_charbuf_reset(name);
    CHKRES(res = ccn_name_from_uri(name, "ccnx:/%C1.M.S.localhost/%C1.M.SRV/ccnd/KEY"));
    CHKRES(res = ccn_get(h, name, templ, 200, resultbuf, &pcobuf, NULL, 0));
    res = ccn_ref_tagged_BLOB(CCN_DTAG_PublisherPublicKeyDigest,
                              resultbuf->buf,
                              pcobuf.offset[CCN_PCO_B_PublisherPublicKeyDigest],
                              pcobuf.offset[CCN_PCO_E_PublisherPublicKeyDigest],
                              &ccndid, &ccndid_size);
    CHKRES(res);
    if (ccndid_size > sizeof(ccndid_storage))
        CHKRES(-1);
    memcpy(ccndid_storage, ccndid, ccndid_size);
    ccndid = ccndid_storage;

    face_instance->action = "newface";
    face_instance->ccnd_id = ccndid;
    face_instance->ccnd_id_size = ccndid_size;
    if (strcmp(argv[optind + 1], "tcp") == 0)
        ipproto = 6;
    else if (strcmp(argv[optind + 1], "udp") == 0)
        ipproto = 17;
    else
        ipproto = atoi(argv[optind + 1]);
    face_instance->descr.ipproto = ipproto; // XXX - 6 = tcp or 17 = udp
    face_instance->descr.address = argv[optind + 2];
    face_instance->descr.port = argv[optind + 3];
    if (face_instance->descr.port == NULL)
        face_instance->descr.port = CCN_DEFAULT_UNICAST_PORT;
    face_instance->descr.mcast_ttl = -1;
    face_instance->lifetime = (~0U) >> 1;

    CHKRES(res = ccnb_append_face_instance(newface, face_instance));
    temp->length = 0;
    CHKRES(ccn_charbuf_putf(temp, "%s/.ccnx/.ccnx_keystore", getenv("HOME")));
    res = ccn_keystore_init(keystore,
                            ccn_charbuf_as_string(temp),
                            "Th1s1sn0t8g00dp8ssw0rd.");
    CHKRES(res);

    ccnb_element_begin(keylocator_templ, CCN_DTAG_SignedInfo);
    ccnb_element_begin(keylocator_templ, CCN_DTAG_KeyLocator);
    ccnb_element_begin(keylocator_templ, CCN_DTAG_Key);
    CHKRES(ccn_append_pubkey_blob(keylocator_templ, ccn_keystore_public_key(keystore)));
    ccnb_element_end(keylocator_templ);	/* </Key> */
    ccnb_element_end(keylocator_templ);	/* </KeyLocator> */
    ccnb_element_end(keylocator_templ);    /* </SignedInfo> */
    sp.template_ccnb = keylocator_templ;
    sp.sp_flags |= CCN_SP_TEMPL_KEY_LOCATOR;
    sp.freshness = expire;
    ccn_charbuf_reset(temp);
    res = ccn_sign_content(h, temp, null_name, &sp,
                           newface->buf, newface->length);
    CHKRES(res);

    /* Create the new face */
    CHKRES(ccn_name_init(name));
    CHKRES(ccn_name_append_str(name, "ccnx"));
    CHKRES(ccn_name_append(name, ccndid, ccndid_size));
    CHKRES(ccn_name_append(name, "newface", 7));
    CHKRES(ccn_name_append(name, temp->buf, temp->length));
    res = ccn_get(h, name, templ, 1000, resultbuf, &pcobuf, NULL, 0);
    if (res < 0) {
        fprintf(stderr, "no response from face creation request\n");
        exit(1);
    }
    ptr = resultbuf->buf;
    length = resultbuf->length;
    res = ccn_content_get_value(resultbuf->buf, resultbuf->length, &pcobuf, &ptr, &length);
    CHKRES(res);
    face_instance = ccn_face_instance_parse(ptr, length);
    if (face_instance == NULL)
        CHKRES(res = -1);
    CHKRES(face_instance->faceid);

    /* Finally, register the prefix */
    ccn_charbuf_reset(name_prefix);
    CHKRES(ccn_name_from_uri(name_prefix, arg));
    forwarding_entry->action = "prefixreg";
    forwarding_entry->name_prefix = name_prefix;
    forwarding_entry->ccnd_id = ccndid;
    forwarding_entry->ccnd_id_size = ccndid_size;
    forwarding_entry->faceid = face_instance->faceid;
    forwarding_entry->flags = -1; /* let ccnd decide */
    forwarding_entry->lifetime = (~0U) >> 1;
    prefixreg = ccn_charbuf_create();
    CHKRES(res = ccnb_append_forwarding_entry(prefixreg, forwarding_entry));
    ccn_charbuf_reset(temp);
    res = ccn_sign_content(h, temp, null_name, &sp,
                           prefixreg->buf, prefixreg->length);
    CHKRES(res);
    CHKRES(ccn_name_init(name));
    CHKRES(ccn_name_append_str(name, "ccnx"));
    CHKRES(ccn_name_append(name, ccndid, ccndid_size));
    CHKRES(ccn_name_append_str(name, "prefixreg"));
    CHKRES(ccn_name_append(name, temp->buf, temp->length));
    res = ccn_get(h, name, templ, 1000, resultbuf, &pcobuf, NULL, 0);
    if (res < 0) {
        fprintf(stderr, "no response from prefix registration request\n");
        exit(1);
    }
    fprintf(stderr, "Prefix %s will be forwarded to face %d\n", arg, face_instance->faceid);

    /* We're about to exit, so don't bother to free everything. */
    ccn_destroy(&h);
    exit(res < 0);
}
Пример #15
0
enum ccn_upcall_res
andana_server_decap_interest(
    struct ccn_closure *selfp,
    enum ccn_upcall_kind kind,
    struct ccn_upcall_info *info)
{
    enum ccn_upcall_res upcall_res = CCN_UPCALL_RESULT_ERR;
    struct andana_server *server = selfp->data;

    struct ccn_proxy *proxy = server->proxy;

    struct ccn_charbuf *new_interest = NULL;
    struct ccn_charbuf *new_name = NULL;

    struct ccn_charbuf *orig_name = NULL;
    struct ccn_indexbuf *orig_name_indexbuf = NULL;
    int orig_name_ncomps;

    char is_session = 0;

    struct hashtb_enumerator ee;
    struct hashtb_enumerator *e = &ee;

    int res;


    DEBUG_PRINT("IN %d %s\n", __LINE__, __func__);

    switch (kind) {
    case CCN_UPCALL_INTEREST:
        DEBUG_PRINT("%d %s received interest\n", __LINE__, __func__);
        break;
    case CCN_UPCALL_INTEREST_TIMED_OUT:
        DEBUG_PRINT("%d %s received interest time out\n", __LINE__, __func__);
        /* Fall through */
    default:
        DEBUG_PRINT("OUT %d %s\n", __LINE__, __func__);
        return(CCN_UPCALL_RESULT_OK);
    }


    /* Extract Name from Interest */

    orig_name_ncomps = ccn_util_extract_name(info->interest_ccnb,
                                             info->interest_comps,
                                             &orig_name,
                                             &orig_name_indexbuf);

#ifdef PROXYDEBUG
    ccn_util_print_pc_fmt(orig_name->buf, orig_name->length);
    DEBUG_PRINT("\n");

    DEBUG_PRINT("Name has %lu comps\n", orig_name_indexbuf->n-1);
#endif

    /*Decapsulate & decrypt Interest. */


    const unsigned char *const_encrypted = NULL;
    unsigned char *encrypted = NULL;
    size_t encrypted_size;

    if (orig_name_ncomps >= 2) {
        const unsigned char *session_check = NULL;
        size_t session_check_size;

        res = ccn_name_comp_get(orig_name->buf,
				orig_name_indexbuf,
				(unsigned int)server->SESSION_FLAG,
				&session_check,
				&session_check_size);

        if (res < 0) {
            DEBUG_PRINT("%d %s Error extracting session check component %lu\n", __LINE__, __func__, server->SESSION_FLAG);
            goto SessionFail;
        } else {
            DEBUG_PRINT("%d %s Extracted component %lu\n", __LINE__, __func__,server->SESSION_FLAG);
        }

        if (session_check_size == strlen("SESSION") &&
            memcmp(session_check, "SESSION", session_check_size) == 0) {

            DEBUG_PRINT("%d %s Session identified\n", __LINE__, __func__);
            is_session = 1;

        } else {
            DEBUG_PRINT("%d %s Not a session\n", __LINE__, __func__);
        }
    }



    /* Decrypt the name (contains a new name and an Interest template) */

    struct ccn_pkey *symkey = NULL;
    struct ccn_charbuf *decrypted = NULL;
    struct ccn_indexbuf *decrypted_comps = ccn_indexbuf_create();

    if (is_session) {

        res = ccn_name_comp_get(orig_name->buf,
				orig_name_indexbuf,
				(unsigned int)server->SESSION_ENC,
				&const_encrypted,
				&encrypted_size);

        if (res < 0) {
            DEBUG_PRINT("%d %s Error extracting encrypted session component %lu\n", __LINE__, __func__, server->SESSION_ENC);
            goto SessionParseFail;
        } else {
            DEBUG_PRINT("%d %s Extracted encrypted session component  %lu\n", __LINE__, __func__, server->SESSION_ENC);
        }

        encrypted = calloc(encrypted_size, sizeof(unsigned char));
        memcpy(encrypted, const_encrypted, encrypted_size);

        ccn_crypto_name_sym_decrypt(server->node_key,
                                    encrypted,
                                    encrypted_size,
                                    &symkey,
                                    &decrypted,
                                    &decrypted_comps);
    } else {

        ccn_name_comp_get(orig_name->buf, orig_name_indexbuf, (unsigned int)server->ENC, &const_encrypted, &encrypted_size);
        encrypted = calloc(encrypted_size, sizeof(unsigned char));
        memcpy(encrypted, const_encrypted, encrypted_size);

        ccn_crypto_name_asym_decrypt(server->privkey,
                                     encrypted,
                                     &symkey,
                                     &decrypted,
                                     &decrypted_comps);
    }

    size_t ncomps = decrypted_comps->n-1;
    const unsigned char *tmpl = NULL;
    size_t tmpl_size;

    res = ccn_name_comp_get(decrypted->buf, decrypted_comps, (unsigned int)ncomps - 1, &tmpl, &tmpl_size);

    if (res < 0) {
        DEBUG_PRINT("ABORT %d %s unable to retrieve component %d\n",
                    __LINE__, __func__, (int)ncomps);
        goto CompExtractFail;
    }

    /* Pull timestamp component (comp 0) */
    const unsigned char *ts_data = NULL;
    size_t ts_size;
    res = ccn_name_comp_get(decrypted->buf, decrypted_comps, 0, &ts_data, &ts_size);

    if (res < 0) {
        goto CompExtractFail;
    }

    struct timeval timestamp;
    ccn_util_extract_timestamp(ts_data, ts_size, &timestamp);

    struct timeval window = {.tv_sec = 1, .tv_usec = 600000};

    if (ccn_util_timestamp_window(&timestamp, &window) == 0) {
        /* Timestamp too far away, this may be a replay attack */
        DEBUG_PRINT("%d %s Timestamp too distant\n", __LINE__, __func__);
        goto TimestampFail;
    }

    new_name = ccn_charbuf_create();
    ccn_name_init(new_name);


    res = ccn_name_append_components(new_name,
                                     decrypted->buf,
                                     decrypted_comps->buf[1],
                                     decrypted_comps->buf[ncomps-1]);

    if (res < 0) {
        DEBUG_PRINT("ABORT %d %s unable to append components\n",
                    __LINE__, __func__);
        goto AppendCompFail;
    }


    /*Construct new Interest*/

    if (tmpl_size == 0) {
        /* Detected default template */
        DEBUG_PRINT("%d %s Using default Interest template\n", __LINE__, __func__);
        new_interest = NULL;
    } else {
        DEBUG_PRINT("%d %s Copying Interest template\n", __LINE__, __func__);
        new_interest = ccn_charbuf_create();
        ccn_charbuf_append(new_interest, tmpl, tmpl_size);
    }

    /*Map new name to that of the original Interest and the requested symkey */

    hashtb_start(server->cname_to_pair, e);
    res = hashtb_seek(e, new_name->buf, new_name->length, 0);

    if (res == HT_NEW_ENTRY) {
        struct andana_server_pair *p = andana_server_pair_init(orig_name, symkey);
        struct andana_server_pair **loc = e->data;
        *loc = p;
    } else if (res == HT_OLD_ENTRY) {
        DEBUG_PRINT("Interest recording found old entry\n");
        goto LookupFail;
    } else {
        DEBUG_PRINT("Error in Interest insertion\n");
        goto LookupFail;
    }





    DEBUG_PRINT("%d %s starting to write new interest\n", __LINE__, __func__);

    res = ccn_express_interest(proxy->handle, new_name, proxy->content_handler, new_interest);

    DEBUG_PRINT("%d %s done to writing new interest\n", __LINE__, __func__);

    if(res != 0) {
        DEBUG_PRINT("ABORT %d %s express interest res = %d\n", __LINE__, __func__, res);
        goto SendFail;
    }

    upcall_res = CCN_UPCALL_RESULT_OK;


SendFail:
LookupFail:

    if (upcall_res == CCN_UPCALL_RESULT_ERR) {
        hashtb_delete(e);
    }

    hashtb_end(e);

    if (new_interest != NULL) {
        ccn_charbuf_destroy(&new_interest);
    }

TimestampFail:
AppendCompFail:
    ccn_charbuf_destroy(&new_name);

CompExtractFail:
    ccn_charbuf_destroy(&decrypted);
    free(encrypted);
    ccn_crypto_symkey_destroy(&symkey);

SessionParseFail:
    ccn_indexbuf_destroy(&decrypted_comps);

SessionFail:
    ccn_charbuf_destroy(&orig_name);
    ccn_indexbuf_destroy(&orig_name_indexbuf);

    DEBUG_PRINT("OUT %d %s\n", __LINE__, __func__);

    return(upcall_res);
}

/**
 * Encapsulate and encrypt returning content objects. Encryption
 * uses the ephemeral symmetric key provided by the user in the original
 * interest (stored in a pair).
 *
 * This node will naturally sign the outgoing content object, thus providing
 * verifiability.
 */

enum ccn_upcall_res
andana_server_encap_content(
    struct ccn_closure *selfp,
    enum ccn_upcall_kind kind,
    struct ccn_upcall_info *info)
{
    enum ccn_upcall_res upcall_res = CCN_UPCALL_RESULT_ERR;
    struct andana_server *server = selfp->data;
    struct ccn_proxy *proxy = server->proxy;

    struct ccn_charbuf *new_name = NULL;
    struct andana_server_pair **pair_ptr = NULL;
    struct ccn_charbuf *new_content = NULL;
    struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT;

    struct hashtb_enumerator ee;
    struct hashtb_enumerator *e = &ee;

    int res;

    DEBUG_PRINT("IN %d %s\n",__LINE__, __func__);

    switch (kind) {
    case CCN_UPCALL_CONTENT:           /**< incoming verified content */
        DEBUG_PRINT("%d %s Incoming verified content\n",__LINE__, __func__);
        break;
    case CCN_UPCALL_CONTENT_UNVERIFIED:/**< content that has not been verified */
        DEBUG_PRINT("%d %s Incoming unverified content\n", __LINE__, __func__);
        break;
    case CCN_UPCALL_CONTENT_BAD:        /**< verification failed */
        DEBUG_PRINT("%d %s Incoming bad content (verification failure)\n", __LINE__, __func__);
        break;

    case CCN_UPCALL_INTEREST_TIMED_OUT:/**< interest timed out */
    {
        DEBUG_PRINT("OUT %d %s Interest timed out\n", __LINE__, __func__);

        const unsigned char *name = info->interest_ccnb + info->pi->offset[CCN_PI_B_Name];
        const size_t length =  info->pi->offset[CCN_PI_E_Name] - info->pi->offset[CCN_PI_B_Name];

        hashtb_start(server->cname_to_pair, e);
        hashtb_seek(e, name, length, 0);
        hashtb_delete(e);
        hashtb_end(e);

        return(CCN_UPCALL_RESULT_OK);
    }
    case CCN_UPCALL_FINAL:/**< handler is about to be deregistered */
        DEBUG_PRINT("OUT %d %s final upcall\n", __LINE__, __func__);
        return(CCN_UPCALL_RESULT_OK);

    case CCN_UPCALL_INTEREST:          /**< incoming interest */
    case CCN_UPCALL_CONSUMED_INTEREST: /**< incoming interest, someone has answered */
    default:
        DEBUG_PRINT("OUT %d %s upcall other kind = %d\n", __LINE__, __func__, kind);
        return(CCN_UPCALL_RESULT_ERR);
    }



    DEBUG_PRINT("%d %s Received content object\n", __LINE__, __func__);

    if (info->content_ccnb == NULL) {
        DEBUG_PRINT("OUT %d %s in content upcall, but no content, check kind: %d\n", __LINE__, __func__, kind);
        return(CCN_UPCALL_RESULT_OK);
    }

    /*Find name in Content Object*/

    new_name = ccn_charbuf_create();
    ccn_name_init(new_name);
    ccn_name_append_components(new_name, info->content_ccnb,
                               info->content_comps->buf[0], info->content_comps->buf[info->matched_comps]);

#ifdef PROXYDEBUG
    DEBUG_PRINT("name matches %d comps\n", info->matched_comps);
    ccn_util_print_pc_fmt(info->content_ccnb + info->pco->offset[CCN_PCO_B_Name],
                          info->pco->offset[CCN_PCO_E_Name] - info->pco->offset[CCN_PCO_B_Name]);
    DEBUG_PRINT("\n");
#endif

    pair_ptr = hashtb_lookup(server->cname_to_pair, new_name->buf, new_name->length);

    if(pair_ptr == NULL) {
        /* No match for name*/
#ifdef PROXYDEBUG
        DEBUG_PRINT("Unsolicited content object with name: ");
        ccn_util_print_pc_fmt(new_name->buf, new_name->length);
        DEBUG_PRINT("\n");
#endif
        goto LookupFail;
    }

    struct ccn_charbuf *orig_name = (*pair_ptr)->name;
    struct ccn_pkey *symkey = (*pair_ptr)->symkey;






    /*Created signed info for new content object*/
    unsigned char *encrypted_content = NULL;
    size_t encrypted_length;

    struct ccn_charbuf *content = ccn_charbuf_create();
    ccn_charbuf_append(content, info->content_ccnb, info->pco->offset[CCN_PCO_E]);

    ccn_crypto_content_encrypt(symkey, content->buf, content->length, &encrypted_content, &encrypted_length);

    new_content = ccn_charbuf_create();
    sp.type = CCN_CONTENT_DATA;

    res = ccn_sign_content(proxy->handle,
                           new_content,
                           orig_name,
                           &sp,
                           encrypted_content,
                           encrypted_length);


    if (ccn_util_validate_content_object(new_content->buf, new_content->length) != 0) {
        DEBUG_PRINT("ABORT %d %s Failed to validated signed content\n", __LINE__, __func__);
        abort();
        goto SignFail;
    } else {
        DEBUG_PRINT("OK %d %s signed content is valid\n", __LINE__, __func__);
    }


    if (res != 0) {
        DEBUG_PRINT("ABORT %d %s Failed to encode ContentObject (res == %d)\n", __LINE__, __func__, res);
        goto SignFail;
    }

    DEBUG_PRINT("%d %s starting content write\n", __LINE__, __func__);

    res = ccn_put(proxy->handle, new_content->buf, new_content->length);

    DEBUG_PRINT("%d %s done content write line\n", __LINE__, __func__);

    if (res < 0) {
        DEBUG_PRINT("ABORT %d %s ccn_put failed (res == %d)\n", __LINE__, __func__, res);
        goto SendFail;
    }

    DEBUG_PRINT("%d %s Reply sent\n", __LINE__, __func__);
    upcall_res = CCN_UPCALL_RESULT_OK;


SendFail:
    hashtb_start(server->cname_to_pair, e);
    hashtb_seek(e, new_name->buf, new_name->length, 0);
    hashtb_delete(e);
    hashtb_end(e);



SignFail:
    ccn_charbuf_destroy(&new_content);
    free(encrypted_content);
    ccn_charbuf_destroy(&content);

LookupFail:
    ccn_charbuf_destroy(&new_name);

    DEBUG_PRINT("OUT %d %s\n", __LINE__, __func__);

    return(upcall_res);
}


/**
 * Clean up and destroy anonymous server object. Expect
 * to be called once at program close.
 *
 * @param pointer to anonymous server to be destroyed
 * @returns 0 (always)
 */

int
andana_server_destroy(struct andana_server **server)
{
    struct andana_server *s = *server;

    free(s->proxy->int_handler);
    free(s->proxy->content_handler);
    ccn_proxy_destroy(&(s->proxy));
    ccn_crypto_pubkey_destroy(&(s->privkey));
    hashtb_destroy(&(s->cname_to_pair));
    free(s);

    return(0);
}
Пример #16
0
/* does that mean the last component is the implicit digest ? */
enum ccn_upcall_res
packet_handler(struct ccn_closure *selfp,
                 enum ccn_upcall_kind upcall_kind,
                 struct ccn_upcall_info *info)
{
	handler_data* h_data = (handler_data*) selfp->data; // Client data returned

	fprintf(stderr, "\nUpcall from %s handle\n", (info->h==(*h_data->ccn_rec))? "receiver":"publisher");
	ccn_set_run_timeout(info->h, 0); // Return to client faster

    switch(upcall_kind) {
    case CCN_UPCALL_FINAL:
        fprintf(stderr, "CCN_UPCALL_FINAL\n");
        return (CCN_UPCALL_RESULT_OK);
    case CCN_UPCALL_INTEREST_TIMED_OUT:
        fprintf(stderr, "CCN_UPCALL_INTEREST_TIMED_OUT\n");
        (*h_data->complete) = 1; 	      // End the main loop, some sort of problem
        return (CCN_UPCALL_RESULT_OK);
    case CCN_UPCALL_CONTENT:
        fprintf(stderr, "CCN_UPCALL_CONTENT\n");
        const unsigned char* content = NULL;
        size_t content_bytes = 0;
        ccn_ref_tagged_BLOB(CCN_DTAG_Content, info->content_ccnb,
							  info->pco->offset[CCN_PCO_B_Content],
							  info->pco->offset[CCN_PCO_E_Content],
							  &content, &content_bytes);
        fprintf(stderr, "\tContent: %s\n", content);
        (*h_data->outstanding_interests)--;
        return (CCN_UPCALL_RESULT_OK);
    case CCN_UPCALL_CONTENT_UNVERIFIED:
        fprintf(stderr, "CCN_UPCALL_CONTENT_UNVERIFIED\n");
        return (CCN_UPCALL_RESULT_OK);
    case CCN_UPCALL_CONTENT_BAD:
        fprintf(stderr, "CCN_UPCALL_CONTENT_BAD\n");
        return (CCN_UPCALL_RESULT_OK);
    case CCN_UPCALL_CONSUMED_INTEREST:
        fprintf(stderr, "CCN_UPCALL_CONSUMED_INTEREST\n");
        return (CCN_UPCALL_RESULT_OK);
    case CCN_UPCALL_INTEREST:
    	fprintf(stderr, "CCN_UPCALL_INTEREST, (matched comp  == %d)\n", info->matched_comps);
    	fprintf(stderr, "                     (interest comps == %zu)\n", info->interest_comps->n);
    	int res = 0;

    	// Corrected 20-May-2011 to support interests with additional components after prefix
    	//
    	if (info->interest_comps->n < 3) {	// Name + signature + implicit digest, minimum
    		fprintf(stderr, "\tnot enough components, %zu<3\n", info->interest_comps->n);
    	} else {
    	// Verify the interest
			res = verify_signed_interest(info->interest_ccnb, info->interest_comps,
										 info->interest_comps->n-2, info->interest_comps->buf[0], info->interest_comps->buf[info->interest_comps->n-2],
										   (*h_data->public_key));
			fprintf(stderr, "\tverify_signed_interest == %d (%s)\n", res, (res==1)?"verified":"unverified");
    	}
		// Based on the results,
		// create and send a reply using default key & algorithm for the receiving handle
		// to sign the content object.
		//
		char* reply_data = (res==1) ? "OK" : "AUTH_FAIL";	// A modest content.
		struct ccn_charbuf* reply = ccn_charbuf_create();
		struct ccn_charbuf* name = ccn_charbuf_create();
		struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT;
	    ccn_name_init(name); // Don't need to create a new name, could just index into the buffer.
	    res = ccn_name_append_components(name, info->interest_ccnb,
	    					info->interest_comps->buf[0], info->interest_comps->buf[info->interest_comps->n - 1]);
		ccn_sign_content(info->h, reply, name, &sp, (void*)reply_data, strlen(reply_data)+1);
		res = ccn_put(info->h, reply->buf, reply->length);
		ccn_charbuf_destroy(&reply);
		ccn_charbuf_destroy(&name);
		if (res >= 0) {
			fprintf (stderr, "\tReturned Content: %s\n", reply_data);
			return (CCN_UPCALL_RESULT_INTEREST_CONSUMED);
		}
        return (CCN_UPCALL_RESULT_OK);
    }
    return (CCN_UPCALL_RESULT_ERR);
}
Пример #17
0
// creates a full structure without action, if proto == "face" only the
// faceid (from cmd_host parameter) and lifetime will be filled in.
struct ccn_face_instance *
parse_ccn_face_instance(struct ccndc_data *self,
                        const char *cmd_proto,
                        const char *cmd_host,     const char *cmd_port,
                        const char *cmd_mcastttl, const char *cmd_mcastif,
                        int freshness)
{
    struct ccn_face_instance *entry;
    struct addrinfo hints = {.ai_family = AF_UNSPEC, .ai_flags = (AI_ADDRCONFIG)};
    struct addrinfo mcasthints = {.ai_family = AF_UNSPEC, .ai_flags = (AI_ADDRCONFIG | AI_NUMERICHOST)};
    struct addrinfo *raddrinfo = NULL;
    struct addrinfo *mcastifaddrinfo = NULL;
    char rhostnamebuf [NI_MAXHOST];
    char rhostportbuf [NI_MAXSERV];
    int off_address = -1, off_port = -1, off_source_address = -1;
    int res;
    int socktype;
    
    entry = calloc(1, sizeof(*entry));
    if (entry == NULL) {
        ccndc_warn(__LINE__, "Fatal error: memory allocation failed");
        goto ExitOnError;
    }
    // allocate storage for Face data
    entry->store = ccn_charbuf_create();
    if (entry->store == NULL) {
        ccndc_warn(__LINE__, "Fatal error: memory allocation failed");
        goto ExitOnError;
    }
    // copy static info
    entry->ccnd_id = (const unsigned char *)self->ccnd_id;
    entry->ccnd_id_size = self->ccnd_id_size;
    
    if (cmd_proto == NULL) {
        ccndc_warn(__LINE__, "command error, missing address type\n");
        goto ExitOnError;
    }
    if (strcasecmp(cmd_proto, "udp") == 0) {
        entry->descr.ipproto = IPPROTO_UDP;
        socktype = SOCK_DGRAM;
    } else if (strcasecmp(cmd_proto, "tcp") == 0) {
        entry->descr.ipproto = IPPROTO_TCP;
        socktype = SOCK_STREAM;
    } else if (strcasecmp(cmd_proto, "face") == 0) {
        errno = 0;
        unsigned long faceid = strtoul(cmd_host, (char **)NULL, 10);
        if (errno == ERANGE || errno == EINVAL || faceid > UINT_MAX || faceid == 0) {
            ccndc_warn(__LINE__, "command error, face number invalid or out of range '%s'\n", cmd_host);
            goto ExitOnError;
        }
        entry->faceid = (unsigned) faceid;
        entry->lifetime = freshness;
        return (entry);
    } else {
        ccndc_warn(__LINE__, "command error, unrecognized address type '%s'\n", cmd_proto);
        goto ExitOnError;
    }
    
    if (cmd_host == NULL) {
        ccndc_warn(__LINE__, "command error, missing hostname\n");
        goto ExitOnError;
    }
    
    if (cmd_port == NULL || cmd_port[0] == 0)
        cmd_port = CCN_DEFAULT_UNICAST_PORT;
    
    hints.ai_socktype = socktype;
    res = getaddrinfo(cmd_host, cmd_port, &hints, &raddrinfo);
    if (res != 0 || raddrinfo == NULL) {
        ccndc_warn(__LINE__, "command error, getaddrinfo for host [%s] port [%s]: %s\n", cmd_host, cmd_port, gai_strerror(res));
        goto ExitOnError;
    }
    res = getnameinfo(raddrinfo->ai_addr, raddrinfo->ai_addrlen,
                      rhostnamebuf, sizeof(rhostnamebuf),
                      rhostportbuf, sizeof(rhostportbuf),
                      NI_NUMERICHOST | NI_NUMERICSERV);
    freeaddrinfo(raddrinfo);
    if (res != 0) {
        ccndc_warn(__LINE__, "command error, getnameinfo: %s\n", gai_strerror(res));
        goto ExitOnError;
    }
    
    off_address = entry->store->length;
    res = ccn_charbuf_append(entry->store, rhostnamebuf, strlen(rhostnamebuf)+1);
    if (res != 0) {
        ccndc_warn(__LINE__, "Cannot append to charbuf");
        goto ExitOnError;
    }
    
    off_port = entry->store->length;
    res = ccn_charbuf_append(entry->store, rhostportbuf, strlen(rhostportbuf)+1);
    if (res != 0) {
        ccndc_warn(__LINE__, "Cannot append to charbuf");
        goto ExitOnError;
    }
    
    entry->descr.mcast_ttl = -1;
    if (cmd_mcastttl != NULL) {
        char *endptr;
        entry->descr.mcast_ttl = strtol(cmd_mcastttl, &endptr, 10); 
        if ((endptr != &cmd_mcastttl[strlen(cmd_mcastttl)]) ||
            entry->descr.mcast_ttl < 0 || entry->descr.mcast_ttl > 255) {
            ccndc_warn(__LINE__, "command error, invalid multicast ttl: %s\n", cmd_mcastttl);
            goto ExitOnError;
        }
    }
    
    if (cmd_mcastif != NULL) {
        res = getaddrinfo(cmd_mcastif, NULL, &mcasthints, &mcastifaddrinfo);
        if (res != 0) {
            ccndc_warn(__LINE__, "command error, incorrect multicat interface [%s]: "
                       "mcastifaddr getaddrinfo: %s\n", cmd_mcastif, gai_strerror(res));
            goto ExitOnError;
        }
        
        res = getnameinfo(mcastifaddrinfo->ai_addr, mcastifaddrinfo->ai_addrlen,
                          rhostnamebuf, sizeof(rhostnamebuf),
                          NULL, 0,
                          NI_NUMERICHOST | NI_NUMERICSERV);
        freeaddrinfo(mcastifaddrinfo);
        if (res != 0) {
            ccndc_warn(__LINE__, "command error, getnameinfo: %s\n", gai_strerror(res));
            goto ExitOnError;
        }
        
        off_source_address = entry->store->length;
        res = ccn_charbuf_append(entry->store, rhostnamebuf, strlen(rhostnamebuf)+1);
        if (res != 0) {
            ccndc_warn(__LINE__, "Cannot append to charbuf");
            goto ExitOnError;
        }
    }
    
    entry->descr.address = (const char *)(entry->store->buf + off_address);
    entry->descr.port = (const char *)(entry->store->buf + off_port);
    if (off_source_address >= 0) {
        entry->descr.source_address = (const char *)(entry->store->buf + off_source_address);
    }
    
    entry->lifetime = freshness;
    
    return entry;
    
ExitOnError:
    ccn_face_instance_destroy(&entry);
    return (NULL);
}

struct ccn_face_instance *
parse_ccn_face_instance_from_face(struct ccndc_data *self,
                                  const char *cmd_faceid)
{
    struct ccn_face_instance *entry = calloc(1, sizeof(*entry));
    
    // allocate storage for Face data
    entry->store = ccn_charbuf_create();
    
    // copy static info
    entry->ccnd_id = (const unsigned char *)self->ccnd_id;
    entry->ccnd_id_size = self->ccnd_id_size;
    
    /* destroy a face - the URI field will hold the face number */
    if (cmd_faceid == NULL) {
        ccndc_warn(__LINE__, "command error, missing face number for destroyface\n");
        goto ExitOnError;
    }
    
    char *endptr;
    int facenumber = strtol(cmd_faceid, &endptr, 10);
    if ((endptr != &cmd_faceid[strlen(cmd_faceid)]) ||
        facenumber < 0) {
        ccndc_warn(__LINE__, "command error invalid face number for destroyface: %d\n", facenumber);
        goto ExitOnError;
    }
    
    entry->faceid = facenumber;
    
    return entry;
    
ExitOnError:
    ccn_face_instance_destroy(&entry);
    return (NULL);
}



///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// "private section
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

int
ccndc_get_ccnd_id(struct ccndc_data *self)
{
    struct ccn_charbuf *name = NULL;
    struct ccn_charbuf *resultbuf = NULL;
    struct ccn_parsed_ContentObject pcobuf = {0};
    char ccndid_uri[] = "ccnx:/%C1.M.S.localhost/%C1.M.SRV/ccnd/KEY";
    const unsigned char *ccndid_result;
    int res = 0;
    
    name = ccn_charbuf_create();
    if (name == NULL) {
        ccndc_warn(__LINE__, "Unable to allocate storage for service locator name charbuf\n");
        return -1;
    }
    
    resultbuf = ccn_charbuf_create();
    if (resultbuf == NULL) {
        ccndc_warn(__LINE__, "Unable to allocate storage for result charbuf");
        res = -1;
        goto Cleanup;
    }
    
    res = ccn_name_from_uri(name, ccndid_uri);
    if (res < 0) {
        ccndc_warn(__LINE__, "Unable to parse service locator URI for ccnd key");
        goto Cleanup;
    }
    
    res = ccn_get(self->ccn_handle,
                  name,
                  self->local_scope_template,
                  4500, resultbuf, &pcobuf, NULL, 0);
    if (res < 0) {
        ccndc_warn(__LINE__, "Unable to get key from ccnd");
        goto Cleanup;
    }
    
    res = ccn_ref_tagged_BLOB (CCN_DTAG_PublisherPublicKeyDigest,
                               resultbuf->buf,
                               pcobuf.offset[CCN_PCO_B_PublisherPublicKeyDigest],
                               pcobuf.offset[CCN_PCO_E_PublisherPublicKeyDigest],
                               &ccndid_result, &self->ccnd_id_size);
    if (res < 0) {
        ccndc_warn(__LINE__, "Unable to parse ccnd response for ccnd id");
        goto Cleanup;
    }
    
    if (self->ccnd_id_size > sizeof (self->ccnd_id))
    {
        ccndc_warn(__LINE__, "Incorrect size for ccnd id in response");
        goto Cleanup;
    }
    
    memcpy(self->ccnd_id, ccndid_result, self->ccnd_id_size);
    
Cleanup:
    ccn_charbuf_destroy(&name);
    ccn_charbuf_destroy(&resultbuf);
    return (res);
}


struct ccn_face_instance *
ccndc_do_face_action(struct ccndc_data *self,
                     const char *action,
                     struct ccn_face_instance *face_instance)
{
    struct ccn_charbuf *newface = NULL;
    struct ccn_charbuf *signed_info = NULL;
    struct ccn_charbuf *temp = NULL;
    struct ccn_charbuf *name = NULL;
    struct ccn_charbuf *resultbuf = NULL;
    struct ccn_parsed_ContentObject pcobuf = {0};
    struct ccn_face_instance *new_face_instance = NULL;
    const unsigned char *ptr = NULL;
    size_t length = 0;
    int res = 0;
    
    face_instance->action = action;
    
    /* Encode the given face instance */
    newface = ccn_charbuf_create();
    ON_NULL_CLEANUP(newface);
    ON_ERROR_CLEANUP(ccnb_append_face_instance(newface, face_instance));
    
    temp = ccn_charbuf_create();
    ON_NULL_CLEANUP(temp);
    res = ccn_sign_content(self->ccn_handle, temp, self->no_name, NULL, newface->buf, newface->length);
    ON_ERROR_CLEANUP(res);
    resultbuf = ccn_charbuf_create();
    ON_NULL_CLEANUP(resultbuf);
    
    /* Construct the Interest name that will create the face */
    name = ccn_charbuf_create();
    ON_NULL_CLEANUP(name);
    ON_ERROR_CLEANUP(ccn_name_init(name));
    ON_ERROR_CLEANUP(ccn_name_append_str(name, "ccnx"));
    ON_ERROR_CLEANUP(ccn_name_append(name, face_instance->ccnd_id, face_instance->ccnd_id_size));
    ON_ERROR_CLEANUP(ccn_name_append_str(name, face_instance->action));
    ON_ERROR_CLEANUP(ccn_name_append(name, temp->buf, temp->length));
    
    res = ccn_get(self->ccn_handle, name, self->local_scope_template, 1000, resultbuf, &pcobuf, NULL, 0);
    ON_ERROR_CLEANUP(res);
    
    ON_ERROR_CLEANUP(ccn_content_get_value(resultbuf->buf, resultbuf->length, &pcobuf, &ptr, &length));
    new_face_instance = ccn_face_instance_parse(ptr, length);
    ON_NULL_CLEANUP(new_face_instance);
    ccn_charbuf_destroy(&newface);
    ccn_charbuf_destroy(&signed_info);
    ccn_charbuf_destroy(&temp);
    ccn_charbuf_destroy(&resultbuf);
    ccn_charbuf_destroy(&name);
    return (new_face_instance);
    
Cleanup:
    ccn_charbuf_destroy(&newface);
    ccn_charbuf_destroy(&signed_info);
    ccn_charbuf_destroy(&temp);
    ccn_charbuf_destroy(&resultbuf);
    ccn_charbuf_destroy(&name);
    ccn_face_instance_destroy(&new_face_instance);
    return (NULL);
}

int
ccndc_do_prefix_action(struct ccndc_data *self,
                       const char *action,
                       struct ccn_forwarding_entry *forwarding_entry)
{
    struct ccn_charbuf *temp = NULL;
    struct ccn_charbuf *resultbuf = NULL;
    struct ccn_charbuf *signed_info = NULL;
    struct ccn_charbuf *name = NULL;
    struct ccn_charbuf *prefixreg = NULL;
    struct ccn_parsed_ContentObject pcobuf = {0};
    struct ccn_forwarding_entry *new_forwarding_entry = NULL;
    
    const unsigned char *ptr = NULL;
    size_t length = 0;
    int res;
    
    forwarding_entry->action = action;
    
    prefixreg = ccn_charbuf_create();
    ON_NULL_CLEANUP(prefixreg);
    ON_ERROR_CLEANUP(ccnb_append_forwarding_entry(prefixreg, forwarding_entry));
    temp = ccn_charbuf_create();
    ON_NULL_CLEANUP(temp);
    res = ccn_sign_content(self->ccn_handle, temp, self->no_name, NULL, prefixreg->buf, prefixreg->length);
    ON_ERROR_CLEANUP(res);    
    resultbuf = ccn_charbuf_create();
    ON_NULL_CLEANUP(resultbuf);
    name = ccn_charbuf_create();
    ON_ERROR_CLEANUP(ccn_name_init(name));
    ON_ERROR_CLEANUP(ccn_name_append_str(name, "ccnx"));
    ON_ERROR_CLEANUP(ccn_name_append(name, forwarding_entry->ccnd_id, forwarding_entry->ccnd_id_size));
    ON_ERROR_CLEANUP(ccn_name_append_str(name, forwarding_entry->action));
    ON_ERROR_CLEANUP(ccn_name_append(name, temp->buf, temp->length));
    res = ccn_get(self->ccn_handle, name, self->local_scope_template, 1000, resultbuf, &pcobuf, NULL, 0);
    ON_ERROR_CLEANUP(res);
    ON_ERROR_CLEANUP(ccn_content_get_value(resultbuf->buf, resultbuf->length, &pcobuf, &ptr, &length));
    new_forwarding_entry = ccn_forwarding_entry_parse(ptr, length);
    ON_NULL_CLEANUP(new_forwarding_entry);
    
    res = new_forwarding_entry->faceid;
    
    ccn_forwarding_entry_destroy(&new_forwarding_entry);
    ccn_charbuf_destroy(&signed_info);
    ccn_charbuf_destroy(&temp);
    ccn_charbuf_destroy(&resultbuf);
    ccn_charbuf_destroy(&name);
    ccn_charbuf_destroy(&prefixreg);
    
    return (res);
    
    /* This is where ON_ERROR_CLEANUP sends us in case of an error
     * and we must free any storage we allocated before returning.
     */
Cleanup:
    ccn_charbuf_destroy(&signed_info);
    ccn_charbuf_destroy(&temp);
    ccn_charbuf_destroy(&resultbuf);
    ccn_charbuf_destroy(&name);
    ccn_charbuf_destroy(&prefixreg);
    
    return (-1);
}
Пример #18
0
int
main (int argc, char *argv[]) {
    struct ccn_charbuf *buffer = ccn_charbuf_create();
    struct ccn_charbuf *signed_info = ccn_charbuf_create();
    struct ccn_skeleton_decoder dd = {0};
    ssize_t res;
    char *outname = NULL;
    int fd;
    int result = 0;
    char * contents[] = {"INVITE sip:[email protected] SIP/2.0\nVia: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bK519044721\nFrom: <sip:[email protected]>;tag=2105643453\nTo: Test User <sip:[email protected]>\nCall-ID: [email protected]\nCSeq: 20 INVITE\nContact: <sip:[email protected]:5060>\nMax-Forwards: 70\nUser-Agent: Linphone-1.7.1/eXosip\nSubject: Phone call\nExpires: 120\nAllow: INVITE, ACK, CANCEL, BYE, OPTIONS, REFER, SUBSCRIBE, NOTIFY, MESSAGE\nContent-Type: application/sdp\nContent-Length:   448\n\nv=0\no=jthornto 123456 654321 IN IP4 127.0.0.1\ns=A conversation\nc=IN IP4 127.0.0.1\nt=0 0\nm=audio 7078 RTP/AVP 111 110 0 3 8 101\na=rtpmap:111 speex/16000/1\na=rtpmap:110 speex/8000/1\na=rtpmap:0 PCMU/8000/1\na=rtpmap:3 GSM/8000/1\na=rtpmap:8 PCMA/8000/1\na=rtpmap:101 telephone-event/8000\na=fmtp:101 0-11\nm=video 9078 RTP/AVP 97 98 99\na=rtpmap:97 theora/90000\na=rtpmap:98 H263-1998/90000\na=fmtp:98 CIF=1;QCIF=1\na=rtpmap:99 MP4V-ES/90000\n", 
 
			 "Quaer #%2d zjduer  badone",
                         "",
                         NULL};
    char * paths[] = { "/sip/protocol/parc.com/domain/foo/principal/invite/verb/[email protected]/id", 
		       "/d/e/f",
                       "/zero/length/content",
                       NULL};
    struct path * cur_path = NULL;
    struct ccn_keystore *keystore = ccn_keystore_create();
    char *home = getenv("HOME");
    char *keystore_suffix = "/.ccnx/.ccnx_keystore";
    char *keystore_name = NULL;

    int i;

    if (argc == 3 && strcmp(argv[1], "-o") == 0) {
	outname = argv[2];
    } else {
	printf("Usage: %s -o <outfilename>\n", argv[0]);
	exit(1);
    }

    if (home == NULL) {
        printf("Unable to determine home directory for keystore\n");
        exit(1);
    }
    keystore_name = calloc(1, strlen(home) + strlen(keystore_suffix) + 1);
    
    strcat(keystore_name, home);
    strcat(keystore_name, keystore_suffix);

    if (0 != ccn_keystore_init(keystore, keystore_name, "Th1s1sn0t8g00dp8ssw0rd.")) {
        printf("Failed to initialize keystore\n");
        exit(1);
    }

    printf("Creating signed_info\n");
    res = ccn_signed_info_create(signed_info,
                                 /*pubkeyid*/ccn_keystore_public_key_digest(keystore),
                                 /*publisher_key_id_size*/ccn_keystore_public_key_digest_length(keystore),
                                 /*datetime*/NULL,
                                 /*type*/CCN_CONTENT_GONE,
                                 /*freshness*/ 42,
                                 /*finalblockid*/NULL,
                                 /*keylocator*/NULL);
    if (res < 0) {
        printf("Failed to create signed_info!\n");
    }
    
    res = ccn_skeleton_decode(&dd, signed_info->buf, signed_info->length);
    if (!(res == signed_info->length && dd.state == 0)) {
        printf("Failed to decode signed_info!  Result %d State %d\n", (int)res, dd.state);
        result = 1;
    }
    memset(&dd, 0, sizeof(dd));
    printf("Done with signed_info\n");

    printf("Encoding sample message data length %d\n", (int)strlen(contents[0]));
    cur_path = path_create(paths[0]);
    if (encode_message(buffer, cur_path, contents[0], strlen(contents[0]), signed_info, ccn_keystore_private_key(keystore))) {
	printf("Failed to encode message!\n");
    } else {
	printf("Encoded sample message length is %d\n", (int)buffer->length);

	res = ccn_skeleton_decode(&dd, buffer->buf, buffer->length);
	if (!(res == buffer->length && dd.state == 0)) {
	    printf("Failed to decode!  Result %d State %d\n", (int)res, dd.state);
	    result = 1;
	}
        if (outname != NULL) {
            fd = open(outname, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU);
            if (fd == -1)
                perror(outname);
            res = write(fd, buffer->buf, buffer->length);
            close(fd);
	}
        if (decode_message(buffer, cur_path, contents[0], strlen(contents[0]), ccn_keystore_public_key(keystore)) != 0) {
	    result = 1;
	}
        printf("Expect signature verification failure: ");
        if (buffer->length >= 20)
            buffer->buf[buffer->length - 20] += 1;
	if (decode_message(buffer, cur_path, contents[0], strlen(contents[0]), ccn_keystore_public_key(keystore)) == 0) {
	    result = 1;
	}
    }
    path_destroy(&cur_path);
    ccn_charbuf_destroy(&buffer);
    printf("Done with sample message\n");
    
    /* Now exercise as unit tests */
    
    for (i = 0; paths[i] != NULL && contents[i] != NULL; i++) {
	printf("Unit test case %d\n", i);
	cur_path = path_create(paths[i]);
	buffer = ccn_charbuf_create();
	if (encode_message(buffer, cur_path, contents[i], strlen(contents[i]), signed_info, ccn_keystore_private_key(keystore))) {
	    printf("Failed encode\n");
            result = 1;
	} else if (decode_message(buffer, cur_path, contents[i], strlen(contents[i]), ccn_keystore_public_key(keystore))) {
	    printf("Failed decode\n");
            result = 1;
	}
	path_destroy(&cur_path);
	ccn_charbuf_destroy(&buffer);
    }
    
    /* Test the uri encode / decode routines */
        
    init_all_chars_percent_encoded();
    const char *uri_tests[] = {
        "_+4", "ccnx:/this/is/a/test",       "",     "ccnx:/this/is/a/test",
        ".+4", "../test2?x=2",              "?x=2", "ccnx:/this/is/a/test2",
        "_-X", "../should/error",           "",     "",
        "_+2", "/missing/scheme",           "",     "ccnx:/missing/scheme",
        ".+0", "../../../../../././#/",     "#/",   "ccnx:/",
        ".+1", all_chars_percent_encoded,   "",     all_chars_percent_encoded_canon,
        "_+1", all_chars_percent_encoded_canon, "", all_chars_percent_encoded_canon,
        ".+4", "ccnx:/.../.%2e./...././.....///?...", "?...", "ccnx:/.../.../..../.....",
        "_-X", "/%3G?bad-pecent-encode",    "",     "",
        "_-X", "/%3?bad-percent-encode",    "",     "",
        "_-X", "/%#bad-percent-encode",    "",     "",
        "_+3", "ccnx://[email protected]:42/ignore/host/part of uri", "", "ccnx:/ignore/host/part%20of%20uri",
        NULL, NULL, NULL, NULL
    };
    const char **u;
    struct ccn_charbuf *uri_out = ccn_charbuf_create();
    buffer = ccn_charbuf_create();
    for (u = uri_tests; *u != NULL; u += 4, i++) {
        printf("Unit test case %d\n", i);
        if (u[0][0] != '.')
            buffer->length = 0;
        res = ccn_name_from_uri(buffer, u[1]);
        if (!expected_res(res, u[0][1])) {
            printf("Failed: ccn_name_from_uri wrong res %d\n", (int)res);
            result = 1;
        }
        if (res >= 0) {
            if (res > strlen(u[1])) {
                printf("Failed: ccn_name_from_uri long res %d\n", (int)res);
                result = 1;
            }
            else if (0 != strcmp(u[1] + res, u[2])) {
                printf("Failed: ccn_name_from_uri expecting leftover '%s', got '%s'\n", u[2], u[1] + res);
                result = 1;
            }
            uri_out->length = 0;
            res = ccn_uri_append(uri_out, buffer->buf, buffer->length, 1);
            if (!expected_res(res, u[0][2])) {
                printf("Failed: ccn_uri_append wrong res %d\n", (int)res);
                result = 1;
            }
            if (res >= 0) {
                if (uri_out->length != strlen(u[3])) {
                    printf("Failed: ccn_uri_append produced wrong number of characters\n");
                    result = 1;
                }
                ccn_charbuf_reserve(uri_out, 1)[0] = 0;
                if (0 != strcmp((const char *)uri_out->buf, u[3])) {
                    printf("Failed: ccn_uri_append produced wrong output\n");
                    printf("Expected: %s\n", u[3]);
                    printf("  Actual: %s\n", (const char *)uri_out->buf);
                    result = 1;
                }
            }
        }
    }
    ccn_charbuf_destroy(&buffer);
    ccn_charbuf_destroy(&uri_out);
    printf("Name marker tests\n");
    do {
        const char *expected_uri = "ccnx:/example.com/.../%01/%FE/%01%02%03%04%05%06%07%08/%FD%10%10%10%10%1F%FF/%00%81";
        const char *expected_chopped_uri = "ccnx:/example.com/.../%01/%FE";
        const char *expected_bumped_uri = "ccnx:/example.com/.../%01/%FF";
        const char *expected_bumped2_uri = "ccnx:/example.com/.../%01/%00%00";

        printf("Unit test case %d\n", i++);
        buffer = ccn_charbuf_create();
        uri_out = ccn_charbuf_create();
        res = ccn_name_init(buffer);
        res |= ccn_name_append_str(buffer, "example.com");
        res |= ccn_name_append_numeric(buffer, CCN_MARKER_NONE, 0);
        res |= ccn_name_append_numeric(buffer, CCN_MARKER_NONE, 1);
        res |= ccn_name_append_numeric(buffer, 0xFE, 0);
        res |= ccn_name_append_numeric(buffer, CCN_MARKER_NONE, 0x0102030405060708ULL);
        res |= ccn_name_append_numeric(buffer, CCN_MARKER_VERSION, 0x101010101FFFULL);
        res |= ccn_name_append_numeric(buffer, CCN_MARKER_SEQNUM, 129);
        res |= ccn_uri_append(uri_out, buffer->buf, buffer->length, 1);
        if (res < 0) {
            printf("Failed: name marker tests had negative res\n");
            result = 1;
        }
        if (0 != strcmp(ccn_charbuf_as_string(uri_out), expected_uri)) {
            printf("Failed: name marker tests produced wrong output\n");
            printf("Expected: %s\n", expected_uri);
            printf("  Actual: %s\n", (const char *)uri_out->buf);
            result = 1;
        }
        res = ccn_name_chop(buffer, NULL, 100);
        if (res != -1) {
            printf("Failed: ccn_name_chop did not produce error \n");
            result = 1;
        }
        res = ccn_name_chop(buffer, NULL, 4);
        if (res != 4) {
            printf("Failed: ccn_name_chop got wrong length\n");
            result = 1;
        }
        uri_out->length = 0;
        ccn_uri_append(uri_out, buffer->buf, buffer->length, 1);
        if (0 != strcmp(ccn_charbuf_as_string(uri_out), expected_chopped_uri)) {
            printf("Failed: ccn_name_chop botch\n");
            printf("Expected: %s\n", expected_chopped_uri);
            printf("  Actual: %s\n", (const char *)uri_out->buf);
            result = 1;
        }
        res = ccn_name_next_sibling(buffer);
        if (res != 4) {
            printf("Failed: ccn_name_next_sibling got wrong length\n");
            result = 1;
        }
        uri_out->length = 0;
        ccn_uri_append(uri_out, buffer->buf, buffer->length, 1);
        if (0 != strcmp(ccn_charbuf_as_string(uri_out), expected_bumped_uri)) {
            printf("Failed: ccn_name_next_sibling botch\n");
            printf("Expected: %s\n", expected_bumped_uri);
            printf("  Actual: %s\n", (const char *)uri_out->buf);
            result = 1;
        }
        ccn_name_next_sibling(buffer);
        uri_out->length = 0;
        ccn_uri_append(uri_out, buffer->buf, buffer->length, 1);
        if (0 != strcmp(ccn_charbuf_as_string(uri_out), expected_bumped2_uri)) {
            printf("Failed: ccn_name_next_sibling botch\n");
            printf("Expected: %s\n", expected_bumped2_uri);
            printf("  Actual: %s\n", (const char *)uri_out->buf);
            result = 1;
        }
        ccn_charbuf_destroy(&buffer);
        ccn_charbuf_destroy(&uri_out);
    } while (0);
    printf("Message digest tests\n");
    do {
        printf("Unit test case %d\n", i++);
        struct ccn_digest *dg = ccn_digest_create(CCN_DIGEST_SHA256);
        if (dg == NULL) {
            printf("Failed: ccn_digest_create returned NULL\n");
            result = 1;
            break;
        }
        printf("Unit test case %d\n", i++);
        const unsigned char expected_digest[] = {
            0xb3, 0x82, 0xcd, 0xb0, 0xe9, 0x5d, 0xf7, 0x3b, 0xe7, 0xdc, 0x19, 0x81, 0x3a, 0xfd, 0xdf, 0x89, 0xfb, 0xd4, 0xd4, 0xa0, 0xdb, 0x11, 0xa6, 0xba, 0x24, 0x16, 0x5b, 0xad, 0x9d, 0x90, 0x72, 0xb0
        };
        unsigned char actual_digest[sizeof(expected_digest)] = {0};
        const char *data = "Content-centric";
        if (ccn_digest_size(dg) != sizeof(expected_digest)) {
            printf("Failed: wrong digest size\n");
            result = 1;
            break;
        }
        printf("Unit test case %d\n", i++);
        ccn_digest_init(dg);
        res = ccn_digest_update(dg, data, strlen(data));
        if (res != 0)
            printf("Warning: check res %d\n", (int)res);
        printf("Unit test case %d\n", i++);
        res = ccn_digest_final(dg, actual_digest, sizeof(expected_digest));
        if (res != 0)
            printf("Warning: check res %d\n", (int)res);
        if (0 != memcmp(actual_digest, expected_digest, sizeof(expected_digest))) {
            printf("Failed: wrong digest\n");
            result = 1;
            break;
        }
    } while (0);
    printf("Really basic PRNG test\n");
    do {
        unsigned char r1[42];
        unsigned char r2[42];
        printf("Unit test case %d\n", i++);
        ccn_add_entropy(&i, sizeof(i), 0); /* Not much entropy, really. */
        ccn_random_bytes(r1, sizeof(r1));
        memcpy(r2, r1, sizeof(r2));
        ccn_random_bytes(r2, sizeof(r2));
        if (0 == memcmp(r1, r2, sizeof(r2))) {
            printf("Failed: badly broken PRNG\n");
            result = 1;
            break;
        }
    } while (0);
    printf("Bloom filter tests\n");
    do {
        unsigned char seed1[4] = "1492";
        const char *a[13] = {
            "one", "two", "three", "four",
            "five", "six", "seven", "eight",
            "nine", "ten", "eleven", "twelve",
            "thirteen"
        };
        struct ccn_bloom *b1 = NULL;
        struct ccn_bloom *b2 = NULL;
        int j, k, t1, t2;
        unsigned short us;
        
        printf("Unit test case %d\n", i++);
        b1 = ccn_bloom_create(13, seed1);
        
        for (j = 0; j < 13; j++)
            if (ccn_bloom_match(b1, a[j], strlen(a[j]))) break;
        if (j < 13) {
            printf("Failed: \"%s\" matched empty Bloom filter\n", a[j]);
            result = 1;
            break;
        }
        printf("Unit test case %d\n", i++);
        for (j = 0; j < 13; j++)
            ccn_bloom_insert(b1, a[j], strlen(a[j]));
        for (j = 0; j < 13; j++)
            if (!ccn_bloom_match(b1, a[j], strlen(a[j]))) break;
        if (j < 13) {
            printf("Failed: \"%s\" not found when it should have been\n", a[j]);
            result = 1;
            break;
        }
        printf("Unit test case %d\n", i++);
        for (j = 0, k = 0; j < 13; j++)
            if (ccn_bloom_match(b1, a[j]+1, strlen(a[j]+1)))
                k++;
        if (k > 0) {
            printf("Mmm, found %d false positives\n", k);
            if (k > 2) {
                result = 1;
                break;
            }
        }
        unsigned char seed2[5] = "aqfb\0";
        for (; seed2[3] <= 'f'; seed2[3]++) {
            printf("Unit test case %d (%4s)    ", i++, seed2);
            b2 = ccn_bloom_create(13, seed2);
            for (j = 0; j < 13; j++)
                ccn_bloom_insert(b2, a[j], strlen(a[j]));
            for (j = 0, k = 0, us = ~0; us > 0; us--) {
                t1 = ccn_bloom_match(b1, &us, sizeof(us));
                t2 = ccn_bloom_match(b2, &us, sizeof(us));
                j += (t1 | t2);
                k += (t1 & t2);
            }
            printf("either=%d both=%d wiresize=%d\n", j, k, ccn_bloom_wiresize(b1));
            if (k > 12) {
                printf("Failed: Bloom seeding may not be effective\n");
                result = 1;
            }
            ccn_bloom_destroy(&b2);
        }
        ccn_bloom_destroy(&b1);
    } while (0);
    printf("ccn_sign_content() tests\n");
    do {
        struct ccn *h = ccn_create();
        struct ccn_charbuf *co = ccn_charbuf_create();
        struct ccn_signing_params sparm = CCN_SIGNING_PARAMS_INIT;
        struct ccn_parsed_ContentObject pco = {0};
        struct ccn_charbuf *name = ccn_charbuf_create();
        
        printf("Unit test case %d\n", i++);
        ccn_name_from_uri(name, "ccnx:/test/data/%00%42");
        res = ccn_sign_content(h, co, name, NULL, "DATA", 4);
        if (res != 0) {
            printf("Failed: res == %d\n", (int)res);
            result = 1;
        }
        sparm.template_ccnb = ccn_charbuf_create();
        res = ccn_parse_ContentObject(co->buf, co->length, &pco, NULL);
        if (res != 0) {
            printf("Failed: ccn_parse_ContentObject res == %d\n", (int)res);
            result = 1;
            break;
        }
        ccn_charbuf_append(sparm.template_ccnb,
            co->buf + pco.offset[CCN_PCO_B_SignedInfo],
            pco.offset[CCN_PCO_E_SignedInfo] - pco.offset[CCN_PCO_B_SignedInfo]);
        sparm.sp_flags = CCN_SP_TEMPL_TIMESTAMP;
        printf("Unit test case %d\n", i++);
        res = ccn_sign_content(h, co, name, &sparm, "DATA", 4);
        if (res != 0) {
            printf("Failed: res == %d\n", (int)res);
            result = 1;
        }
        printf("Unit test case %d\n", i++);
        sparm.sp_flags = -1;
        res = ccn_sign_content(h, co, name, &sparm, "DATA", 4);
        if (res != -1) {
            printf("Failed: res == %d\n", (int)res);
            result = 1;
        }
        ccn_charbuf_destroy(&name);
        ccn_charbuf_destroy(&sparm.template_ccnb);
        ccn_charbuf_destroy(&co);
        ccn_destroy(&h);
    } while (0);
    printf("link tests\n");
    do {
        struct ccn_charbuf *l = ccn_charbuf_create();
        struct ccn_charbuf *name = ccn_charbuf_create();
        struct ccn_parsed_Link pl = {0};
        struct ccn_buf_decoder decoder;
        struct ccn_buf_decoder *d;
        struct ccn_indexbuf *comps = ccn_indexbuf_create();
        printf("Unit test case %d\n", i++);
        ccn_name_from_uri(name, "ccnx:/test/link/name");
        ccnb_append_Link(l, name, "label", NULL);
        d = ccn_buf_decoder_start(&decoder, l->buf, l->length);
        res = ccn_parse_Link(d, &pl, comps);
        if (res != 3 /* components in name */) {
            printf("Failed: ccn_parse_Link res == %d\n", (int)res);
            result = 1;
        }        
    } while (0);
    
    exit(result);
}
Пример #19
0
int
sign_content_with_user_defined_keystore(struct ccn_charbuf *content_name,
										struct ccn_charbuf *resultbuf,
										const void *data,
										size_t data_size,
										char *keystore_path,
										char *keystore_passphrase,
										char *key_repo_name,
										char *site_name,
										char *router_name){
	
	if ( nlsr->debugging )
		printf("sign_content_with_user_defined_keystore called\n");

	
	int res;


	struct ccn_charbuf * pubid_out=ccn_charbuf_create();
	struct ccn_charbuf * keyname;

	
	struct ccn_keystore *keystore = NULL;
	keystore=ccn_keystore_create();
	res=ccn_keystore_init(keystore, keystore_path,keystore_passphrase );
	if ( res < 0 ){
		if ( nlsr->debugging )
			printf("Error in initiating keystore :(\n");
		ccn_keystore_destroy(&keystore);
		return -1;
	}
	

	res=ccn_load_private_key	(nlsr->ccn,
							keystore_path,
							keystore_passphrase,
							pubid_out);

	if(res < 0 ){
		if ( nlsr->debugging )
			printf("Error in loading keystore :( \n");
		ccn_charbuf_destroy(&pubid_out);
		return -1;
	}

	char *baseuri=(char *)calloc(strlen(key_repo_name)+strlen(site_name)+
				  strlen(router_name)+strlen("/%C1.R.N.Start")+5,sizeof(char));
	memcpy(baseuri,key_repo_name,strlen(key_repo_name)+1);
	if ( site_name[0] != '/')
		memcpy(baseuri+strlen(baseuri),"/",1);
	memcpy(baseuri+strlen(baseuri),site_name,strlen(site_name)+1);
	memcpy(baseuri+strlen(baseuri),"/%C1.R.N.Start",strlen("/%C1.R.N.Start"));
	memcpy(baseuri+strlen(baseuri),router_name,strlen(router_name)+1);
	baseuri[strlen(baseuri)]='\0';
	

	keyname=ccn_charbuf_create();
	if(keyname == NULL ){
		ccn_charbuf_destroy(&pubid_out);
		free(baseuri);
		return -1;
	}
	ccn_name_from_uri(keyname,baseuri);
	if ( res < 0 ){
		if ( nlsr->debugging )
			printf("Bad URI format: %s\n",baseuri);
		ccn_charbuf_destroy(&pubid_out);
		ccn_charbuf_destroy(&keyname);
		free(baseuri);
		return -1;		
	}
	
	ccn_name_append_str(keyname,"nlsr");
	struct ccn_charbuf *keyid = ccn_charbuf_create();
	ccn_charbuf_append_value(keyid, CCN_MARKER_CONTROL, 1);
	ccn_charbuf_append_string(keyid, ".M.K");
	ccn_charbuf_append_value(keyid, 0, 1);
	ccn_charbuf_append_charbuf(keyid, pubid_out);
	ccn_name_append(keyname, keyid->buf, keyid->length);
	
	

	struct ccn_charbuf *uri = ccn_charbuf_create();
	ccn_uri_append(uri, keyname->buf, keyname->length, 0);
	if ( nlsr->debugging )
		printf("Key Name Included when processing content: %s\n", ccn_charbuf_as_string(uri));
	ccn_charbuf_destroy(&uri);	

	struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT;
	sp.type = CCN_CONTENT_DATA;
 	sp.template_ccnb = ccn_charbuf_create();
  	ccn_charbuf_append_tt(sp.template_ccnb, CCN_DTAG_SignedInfo, CCN_DTAG);
	ccn_charbuf_append_tt(sp.template_ccnb, CCN_DTAG_KeyLocator, CCN_DTAG);
  	ccn_charbuf_append_tt(sp.template_ccnb, CCN_DTAG_KeyName, CCN_DTAG);
  	ccn_charbuf_append(sp.template_ccnb, keyname->buf, keyname->length); 
	ccn_charbuf_append_closer(sp.template_ccnb); // KeyName closer
  	ccn_charbuf_append_closer(sp.template_ccnb); // KeyLocator closer
  	ccn_charbuf_append_closer(sp.template_ccnb); // SignedInfo closer
	
	sp.sp_flags |= CCN_SP_TEMPL_KEY_LOCATOR;
	sp.sp_flags |= CCN_SP_FINAL_BLOCK;
	sp.freshness = 60;


	if (pubid_out->length != sizeof(sp.pubid)){
		if ( nlsr->debugging )
			printf("Size of pubid and sp.pubid is not equal");
		ccn_charbuf_destroy(&keyname);
		ccn_charbuf_destroy(&pubid_out);
		free(baseuri);
		return -1;
	}
	
	memcpy(sp.pubid, pubid_out->buf, pubid_out->length);
	


	res=ccn_sign_content(nlsr->ccn,resultbuf,content_name,&sp,data,data_size);
	if( res < 0 ){
		if ( nlsr->debugging )
			printf("Content signing error \n");
		ccn_charbuf_destroy(&sp.template_ccnb);
		ccn_charbuf_destroy(&keyid);
		ccn_charbuf_destroy(&keyname);
		ccn_charbuf_destroy(&pubid_out);
		free(baseuri);
 		return -1;
	}

	ccn_charbuf_destroy(&sp.template_ccnb);
	ccn_charbuf_destroy(&keyid);
	ccn_charbuf_destroy(&keyname);
	ccn_charbuf_destroy(&pubid_out);
	free(baseuri);
 	return 0;
}
Пример #20
0
int
unit_tests_for_signing(struct ccn *h, int *ip, int symmetric)
{
    struct ccn_charbuf *co = ccn_charbuf_create();
    struct ccn_charbuf *co2 = ccn_charbuf_create();
    struct ccn_signing_params sparm = CCN_SIGNING_PARAMS_INIT;
    struct ccn_parsed_ContentObject pco = {0};
    struct ccn_parsed_ContentObject pco2 = {0};
    struct ccn_charbuf *name = ccn_charbuf_create();
    int res;
    int result = 0;

    ccn_name_from_uri(name, "ccnx:/test/data/%00%42");
    res = ccn_sign_content(h, co, name, NULL, "DATA", 4);
    if (res != 0) {
        printf("Failed: res == %d\n", (int)res);
        result = 1;
    }
    sparm.template_ccnb = ccn_charbuf_create();
    res = ccn_parse_ContentObject(co->buf, co->length, &pco, NULL);
    if (res != 0) {
        printf("Failed: ccn_parse_ContentObject res == %d\n", (int)res);
        result = 1;
        goto Bail;
    }
    ccn_charbuf_append(sparm.template_ccnb,
        co->buf + pco.offset[CCN_PCO_B_SignedInfo],
        pco.offset[CCN_PCO_E_SignedInfo] - pco.offset[CCN_PCO_B_SignedInfo]);
    sparm.sp_flags = CCN_SP_TEMPL_TIMESTAMP;
    printf("Unit test case %d\n", (*ip)++);
    res = ccn_sign_content(h, co2, name, &sparm, "DATA", 4);
    if (res != 0) {
        printf("Failed: res == %d\n", (int)res);
        result = 1;
    }
    res = ccn_parse_ContentObject(co2->buf, co2->length, &pco2, NULL);
    if (res != 0) {
        printf("Failed to parse: res == %d\n", (int)res);
        result = 1;
    }
    printf("Unit test case %d\n", (*ip)++);
    sparm.sp_flags = -1;
    res = ccn_sign_content(h, co, name, &sparm, "DATA", 4);
    if (res != -1) {
        printf("Failed: res == %d\n", (int)res);
        result = 1;
    }

    /*
     * We can run this test with symmetric keys if the problem of being able
     * to store both a keystore and its associated key in the corresponding
     * hashtables of a handle can be solved.
     */
    if (!symmetric) {
        printf("Unit test case %d\n", (*ip)++);
        res = ccn_verify_content(h, co->buf, &pco);
        if (res != 0) {
            printf("Failed: res == %d\n", (int)res);
            result = 1;
        }
    }
Bail:
    ccn_charbuf_destroy(&name);
    ccn_charbuf_destroy(&sparm.template_ccnb); 
    ccn_charbuf_destroy(&co);
    ccn_charbuf_destroy(&co2);
    return result;
}
Пример #21
0
static int
write_slice(struct ccn *h,
            struct ccns_slice *slice,
            struct ccn_charbuf *name) {
    struct ccn_charbuf *content = NULL;
    unsigned char *cbuf = NULL;
    size_t clength = 0;
    struct ccn_charbuf *sw = NULL;
    struct ccn_charbuf *templ = NULL;
    struct ccn_charbuf *cob = NULL;
    struct ccn_signing_params sparm = CCN_SIGNING_PARAMS_INIT;
    struct ccn_closure *wc = NULL;
    int res;

    sw = ccn_charbuf_create_n(32 + name->length);
    if (sw == NULL) {
        res = -1;
        goto Cleanup;
    }
    ccn_charbuf_append_charbuf(sw, name);
    ccn_name_chop(sw, NULL, -1); // remove segment number
    ccn_name_from_uri(sw, "%C1.R.sw");
    ccn_name_append_nonce(sw);

    // create and sign the content object
    cob = ccn_charbuf_create();
    if (cob == NULL) {
        res = -1;
        goto Cleanup;
    }
    if (slice != NULL) {
        content = ccn_charbuf_create();
        if (content == NULL) {
            res = -1;
            goto Cleanup;
        }
        res = append_slice(content, slice);
        if (res < 0)
            goto Cleanup;
        cbuf = content->buf;
        clength = content->length;
    } else {
        sparm.type = CCN_CONTENT_GONE;
    }

    sparm.sp_flags = CCN_SP_FINAL_BLOCK;
    res = ccn_sign_content(h, cob, name, &sparm, cbuf, clength);
    if (res < 0)
        goto Cleanup;
    // establish handler for interest in the slice content object
    wc = calloc(1, sizeof(*wc));
    if (wc == NULL) {
        res = -1;
        goto Cleanup;
    }
    wc->p = &write_interest_handler;
    wc->data = cob;
    res = ccn_set_interest_filter(h, name, wc);
    if (res < 0)
        goto Cleanup;
    templ = make_scope1_template();
    if (templ == NULL) {
        res = -1;
        goto Cleanup;
    }
    res = ccn_get(h, sw, templ, 1000, NULL, NULL, NULL, 0);
    if (res < 0)
        goto Cleanup;
    ccn_run(h, 1000); // give the repository a chance to fetch the data
    if (wc->intdata != 1) {
        res = -1;
        goto Cleanup;
    }
    res = 0;
Cleanup:
    ccn_set_interest_filter(h, name, NULL);
    if (wc != NULL)
        free(wc);
    ccn_charbuf_destroy(&cob);
    ccn_charbuf_destroy(&content);
    ccn_charbuf_destroy(&sw);
    ccn_charbuf_destroy(&templ);
    return (res);
}
Пример #22
0
int
main(int argc, char **argv)
{
    const char *progname = argv[0];
    struct ccn *ccn = NULL;
    struct ccn_charbuf *name = NULL;
    struct ccn_charbuf *pname = NULL;
    struct ccn_charbuf *temp = NULL;
    struct ccn_charbuf *extopt = NULL;
    long expire = -1;
    int versioned = 0;
    size_t blocksize = 8*1024;
    int status = 0;
    int res;
    ssize_t read_res;
    unsigned char *buf = NULL;
    enum ccn_content_type content_type = CCN_CONTENT_DATA;
    struct ccn_closure in_interest = {.p=&incoming_interest};
    const char *postver = NULL;
    const char *key_uri = NULL;
    int force = 0;
    int verbose = 0;
    int timeout = -1;
    int setfinal = 0;
    int prefixcomps = -1;
    int fd;
    struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT;
    
    while ((res = getopt(argc, argv, "e:fhk:lvV:p:t:w:x:")) != -1) {
        switch (res) {
            case 'e':
                if (extopt == NULL)
                    extopt = ccn_charbuf_create();
                fd = open(optarg, O_RDONLY);
                if (fd < 0) {
                    perror(optarg);
                    exit(1);
                }
                for (;;) {
                    read_res = read(fd, ccn_charbuf_reserve(extopt, 64), 64);
                    if (read_res <= 0)
                        break;
                    extopt->length += read_res;
                }
                if (read_res < 0)
                    perror(optarg);
                close(fd);
                break;
            case 'f':
                force = 1;
                break;
            case 'l':
                setfinal = 1; // set FinalBlockID to last comp of name
                break;
            case 'k':
                key_uri = optarg;
                break;
            case 'p':
                prefixcomps = atoi(optarg);
                if (prefixcomps < 0)
                    usage(progname);
                break;
            case 'x':
                expire = atol(optarg);
                if (expire <= 0)
                    usage(progname);
                break;
            case 'v':
                verbose = 1;
                break;
            case 'V':
                versioned = 1;
                postver = optarg;
                if (0 == memcmp(postver, "%00", 3))
                    setfinal = 1;
                break;
            case 'w':
                timeout = atol(optarg);
                if (timeout <= 0)
                    usage(progname);
                timeout *= 1000;
                break;
            case 't':
                if (0 == strcasecmp(optarg, "DATA")) {
                    content_type = CCN_CONTENT_DATA;
                    break;
                }
                if (0 == strcasecmp(optarg, "ENCR")) {
                    content_type = CCN_CONTENT_ENCR;
                    break;
                }
                if (0 == strcasecmp(optarg, "GONE")) {
                    content_type = CCN_CONTENT_GONE;
                    break;
                }
                if (0 == strcasecmp(optarg, "KEY")) {
                    content_type = CCN_CONTENT_KEY;
                    break;
                }
                if (0 == strcasecmp(optarg, "LINK")) {
                    content_type = CCN_CONTENT_LINK;
                    break;
                }
                if (0 == strcasecmp(optarg, "NACK")) {
                    content_type = CCN_CONTENT_NACK;
                    break;
                }
                content_type = atoi(optarg);
                if (content_type > 0 && content_type <= 0xffffff)
                    break;
                fprintf(stderr, "Unknown content type %s\n", optarg);
                /* FALLTHRU */
            default:
            case 'h':
                usage(progname);
                break;
        }
    }
    argc -= optind;
    argv += optind;
    if (argv[0] == NULL)
        usage(progname);
    name = ccn_charbuf_create();
    res = ccn_name_from_uri(name, argv[0]);
    if (res < 0) {
        fprintf(stderr, "%s: bad ccn URI: %s\n", progname, argv[0]);
        exit(1);
    }
    if (argv[1] != NULL)
        fprintf(stderr, "%s warning: extra arguments ignored\n", progname);
    
    /* Preserve the original prefix, in case we add versioning,
     * but trim it down if requested for the interest filter registration
     */
    pname = ccn_charbuf_create();
    ccn_charbuf_append(pname, name->buf, name->length);
    if (prefixcomps >= 0) {
        res = ccn_name_chop(pname, NULL, prefixcomps);
        if (res < 0) {
            fprintf(stderr, "%s: unable to trim name to %d component%s.\n",
                    progname, prefixcomps, prefixcomps == 1 ? "" : "s");
            exit(1);
        }
    }
    /* Connect to ccnd */
    ccn = ccn_create();
    if (ccn_connect(ccn, NULL) == -1) {
        perror("Could not connect to ccnd");
        exit(1);
    }

    /* Read the actual user data from standard input */
    buf = calloc(1, blocksize);
    read_res = read_full(0, buf, blocksize);
    if (read_res < 0) {
        perror("read");
        read_res = 0;
        status = 1;
    }
        
    /* Tack on the version component if requested */
    if (versioned) {
        res = ccn_create_version(ccn, name, CCN_V_REPLACE | CCN_V_NOW | CCN_V_HIGH, 0, 0);
        if (res < 0) {
            fprintf(stderr, "%s: ccn_create_version() failed\n", progname);
            exit(1);
        }
        if (postver != NULL) {
            res = ccn_name_from_uri(name, postver);
            if (res < 0) {
                fprintf(stderr, "-V %s: invalid name suffix\n", postver);
                exit(0);
            }
        }
    }
    temp = ccn_charbuf_create();
    
    /* Ask for a FinalBlockID if appropriate. */
    if (setfinal)
        sp.sp_flags |= CCN_SP_FINAL_BLOCK;
    
    if (res < 0) {
        fprintf(stderr, "Failed to create signed_info (res == %d)\n", res);
        exit(1);
    }
    
    /* Set content type */
    sp.type = content_type;
    
    /* Set freshness */
    if (expire >= 0) {
        if (sp.template_ccnb == NULL) {
            sp.template_ccnb = ccn_charbuf_create();
            ccn_charbuf_append_tt(sp.template_ccnb, CCN_DTAG_SignedInfo, CCN_DTAG);
        }
        else if (sp.template_ccnb->length > 0) {
            sp.template_ccnb->length--;
        }
        ccnb_tagged_putf(sp.template_ccnb, CCN_DTAG_FreshnessSeconds, "%ld", expire);
        sp.sp_flags |= CCN_SP_TEMPL_FRESHNESS;
        ccn_charbuf_append_closer(sp.template_ccnb);
    }
    
    /* Set key locator, if supplied */
    if (key_uri != NULL) {
        struct ccn_charbuf *c = ccn_charbuf_create();
        res = ccn_name_from_uri(c, key_uri);
        if (res < 0) {
            fprintf(stderr, "%s is not a valid ccnx URI\n", key_uri);
            exit(1);
        }
        if (sp.template_ccnb == NULL) {
            sp.template_ccnb = ccn_charbuf_create();
            ccn_charbuf_append_tt(sp.template_ccnb, CCN_DTAG_SignedInfo, CCN_DTAG);
        }
        else if (sp.template_ccnb->length > 0) {
            sp.template_ccnb->length--;
        }
        ccn_charbuf_append_tt(sp.template_ccnb, CCN_DTAG_KeyLocator, CCN_DTAG);
        ccn_charbuf_append_tt(sp.template_ccnb, CCN_DTAG_KeyName, CCN_DTAG);
        ccn_charbuf_append(sp.template_ccnb, c->buf, c->length);
        ccn_charbuf_append_closer(sp.template_ccnb);
        ccn_charbuf_append_closer(sp.template_ccnb);
        sp.sp_flags |= CCN_SP_TEMPL_KEY_LOCATOR;
        ccn_charbuf_append_closer(sp.template_ccnb);
        ccn_charbuf_destroy(&c);
    }

    if (extopt != NULL && extopt->length > 0) {
        if (sp.template_ccnb == NULL) {
            sp.template_ccnb = ccn_charbuf_create();
            ccn_charbuf_append_tt(sp.template_ccnb, CCN_DTAG_SignedInfo, CCN_DTAG);
        }
        else if (sp.template_ccnb->length > 0) {
            sp.template_ccnb->length--;
        }
        ccnb_append_tagged_blob(sp.template_ccnb, CCN_DTAG_ExtOpt,
                                extopt->buf, extopt->length);
        sp.sp_flags |= CCN_SP_TEMPL_EXT_OPT;
        ccn_charbuf_append_closer(sp.template_ccnb);
    }
    
    /* Create the signed content object, ready to go */
    temp->length = 0;
    res = ccn_sign_content(ccn, temp, name, &sp, buf, read_res);
    if (res != 0) {
        fprintf(stderr, "Failed to encode ContentObject (res == %d)\n", res);
        exit(1);
    }
    if (read_res == blocksize) {
        read_res = read_full(0, buf, 1);
        if (read_res == 1) {
            fprintf(stderr, "%s: warning - truncated data\n", argv[0]);
            status = 1;
        }
    }
    free(buf);
    buf = NULL;
    if (force) {
        /* At user request, send without waiting to see an interest */
        res = ccn_put(ccn, temp->buf, temp->length);
        if (res < 0) {
            fprintf(stderr, "ccn_put failed (res == %d)\n", res);
            exit(1);
        }
    }
    else {
        in_interest.data = temp;
        /* Set up a handler for interests */
        res = ccn_set_interest_filter(ccn, pname, &in_interest);
        if (res < 0) {
            fprintf(stderr, "Failed to register interest (res == %d)\n", res);
            exit(1);
        }
        res = ccn_run(ccn, timeout);
        if (in_interest.intdata == 0) {
            if (verbose)
                fprintf(stderr, "Nobody's interested\n");
            exit(1);
        }
    }
    
    if (verbose) {
        struct ccn_charbuf *uri = ccn_charbuf_create();
        uri->length = 0;
        ccn_uri_append(uri, name->buf, name->length, 1);
        printf("wrote %s\n", ccn_charbuf_as_string(uri));
        ccn_charbuf_destroy(&uri);
    }
    ccn_destroy(&ccn);
    ccn_charbuf_destroy(&name);
    ccn_charbuf_destroy(&pname);
    ccn_charbuf_destroy(&temp);
    ccn_charbuf_destroy(&sp.template_ccnb);
    ccn_charbuf_destroy(&extopt);
    exit(status);
}