Example #1
0
int get_default_keys(struct ccn* h, struct ccn_signing_params* p, struct ccn_keystore** keystore, struct ccn_pkey** public_key,
		unsigned char** public_key_digest, size_t* public_key_digest_length, struct ccn_pkey** private_key) {
	// These structures are supposed to be internal to the libs but
	// there doesn't appear to be an API to deal with the keystores -
	// We could use ccn_keystore_init but seem to have to know just
	// as many implementation details. See ccnsendchunks.c
	struct hashtb_enumerator ee;
	struct hashtb_enumerator *e = ⅇ
	int res = 0;
	hashtb_start(h->keystores, e);
		if (hashtb_seek(e, p->pubid, sizeof(p->pubid), 0) != HT_OLD_ENTRY) {
			fprintf(stderr,"No default keystore?\n");
			res = -1;
		} else {
			struct ccn_keystore **pk = e->data;
			(*keystore) = *pk;
			(*public_key) = (struct ccn_pkey*) ccn_keystore_public_key(*keystore);
			(*private_key) = (struct ccn_pkey*) ccn_keystore_private_key(*keystore);
			(*public_key_digest) = (unsigned char*) ccn_keystore_public_key_digest(*keystore);
			(*public_key_digest_length) = ccn_keystore_public_key_digest_length(*keystore);
		}
	hashtb_end(e);
	return(res);
}
Example #2
0
int
main(int argc, char **argv)
{
    const char *progname = argv[0];
    struct ccn *ccn = NULL;
    struct ccn_charbuf *root = NULL;
    struct ccn_charbuf *name = NULL;
    struct ccn_charbuf *temp = NULL;
    struct ccn_charbuf *templ = NULL;
    struct ccn_charbuf *signed_info = NULL;
    struct ccn_charbuf *keylocator = NULL;
    struct ccn_charbuf *finalblockid = NULL;
    struct ccn_keystore *keystore = NULL;
    long expire = -1;
    long blocksize = 1024;
    int i;
    int status = 0;
    int res;
    ssize_t read_res;
    unsigned char *buf = NULL;
    struct mydata mydata = { 0 };
    struct ccn_closure in_content = {.p=&incoming_content, .data=&mydata};
    struct ccn_closure in_interest = {.p=&incoming_interest, .data=&mydata};
    while ((res = getopt(argc, argv, "hx:b:")) != -1) {
        switch (res) {
            case 'x':
                expire = atol(optarg);
                if (expire <= 0)
                    usage(progname);
                break;
	    case 'b':
	        blocksize = atol(optarg);
                break;
            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);

    ccn = ccn_create();
    if (ccn_connect(ccn, NULL) == -1) {
        perror("Could not connect to ccnd");
        exit(1);
    }
    
    buf = calloc(1, blocksize);
    root = name;
    name = ccn_charbuf_create();
    temp = ccn_charbuf_create();
    templ = ccn_charbuf_create();
    signed_info = ccn_charbuf_create();
    keystore = ccn_keystore_create();
    temp->length = 0;
    ccn_charbuf_putf(temp, "%s/.ccnx/.ccnx_keystore", getenv("HOME"));
    res = ccn_keystore_init(keystore,
                            ccn_charbuf_as_string(temp),
                            "Th1s1sn0t8g00dp8ssw0rd.");
    if (res != 0) {
        printf("Failed to initialize keystore\n");
        exit(1);
    }
    
    name->length = 0;
    ccn_charbuf_append(name, root->buf, root->length);
    
    /* Set up a handler for interests */
    ccn_set_interest_filter(ccn, name, &in_interest);
    
    /* Initiate check to see whether there is already something there. */
    temp->length = 0;
    ccn_charbuf_putf(temp, "%d", 0);
    ccn_name_append(name, temp->buf, temp->length);
    templ->length = 0;
    ccn_charbuf_append_tt(templ, CCN_DTAG_Interest, CCN_DTAG);
    ccn_charbuf_append_tt(templ, CCN_DTAG_Name, CCN_DTAG);
    ccn_charbuf_append_closer(templ); /* </Name> */
    ccn_charbuf_append_tt(templ, CCN_DTAG_MaxSuffixComponents, CCN_DTAG);
    ccn_charbuf_append_tt(templ, 1, CCN_UDATA);
    ccn_charbuf_append(templ, "1", 1);
    ccn_charbuf_append_closer(templ); /* </MaxSuffixComponents> */
    // XXX - use pubid
    ccn_charbuf_append_closer(templ); /* </Interest> */
    res = ccn_express_interest(ccn, name, &in_content, templ);
    if (res < 0) abort();
    
    /* Construct a key locator contining the key itself */
    keylocator = ccn_charbuf_create();
    ccn_charbuf_append_tt(keylocator, CCN_DTAG_KeyLocator, CCN_DTAG);
    ccn_charbuf_append_tt(keylocator, CCN_DTAG_Key, CCN_DTAG);
    res = ccn_append_pubkey_blob(keylocator, ccn_keystore_public_key(keystore));
    if (res < 0)
        ccn_charbuf_destroy(&keylocator);
    else {
        ccn_charbuf_append_closer(keylocator); /* </Key> */
        ccn_charbuf_append_closer(keylocator); /* </KeyLocator> */
    }
    
    for (i = 0;; i++) {
        read_res = read_full(0, buf, blocksize);
        if (read_res < 0) {
            perror("read");
            read_res = 0;
            status = 1;
        }
        signed_info->length = 0;
        if (read_res < blocksize) {
            temp->length = 0;
            ccn_charbuf_putf(temp, "%d", i);
            ccn_name_append(name, temp->buf, temp->length);
            finalblockid = ccn_charbuf_create();
            ccn_charbuf_append_tt(finalblockid, temp->length, CCN_BLOB);
            ccn_charbuf_append(finalblockid, temp->buf, temp->length);
        }
        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_DATA,
                                     /*freshness*/ expire,
                                     finalblockid,
                                     keylocator);
        /* Put the keylocator in the first block only. */
        ccn_charbuf_destroy(&keylocator);
        if (res < 0) {
            fprintf(stderr, "Failed to create signed_info (res == %d)\n", res);
            exit(1);
        }
        name->length = 0;
        ccn_charbuf_append(name, root->buf, root->length);
        temp->length = 0;
        ccn_charbuf_putf(temp, "%d", i);
        ccn_name_append(name, temp->buf, temp->length);
        temp->length = 0;
        ccn_charbuf_append(temp, buf, read_res);
        temp->length = 0;
        res = ccn_encode_ContentObject(temp,
                                       name,
                                       signed_info,
                                       buf,
                                       read_res,
                                       NULL,
                                       ccn_keystore_private_key(keystore));
        if (res != 0) {
            fprintf(stderr, "Failed to encode ContentObject (res == %d)\n", res);
            exit(1);
        }
        if (i == 0) {
            /* Finish check for old content */
            if (mydata.content_received == 0)
                ccn_run(ccn, 100);
            if (mydata.content_received > 0) {
                fprintf(stderr, "%s: name is in use: %s\n", progname, argv[0]);
                exit(1);
            }
            mydata.outstanding++; /* the first one is free... */
        }
        res = ccn_put(ccn, temp->buf, temp->length);
        if (res < 0) {
            fprintf(stderr, "ccn_put failed (res == %d)\n", res);
            exit(1);
        }
        if (read_res < blocksize)
            break;
        if (mydata.outstanding > 0)
            mydata.outstanding--;
        else
            res = 10;
        res = ccn_run(ccn, res * 100);
        if (res < 0) {
            status = 1;
            break;
        }
    }
    
    free(buf);
    buf = NULL;
    ccn_charbuf_destroy(&root);
    ccn_charbuf_destroy(&name);
    ccn_charbuf_destroy(&temp);
    ccn_charbuf_destroy(&signed_info);
    ccn_charbuf_destroy(&finalblockid);
    ccn_keystore_destroy(&keystore);
    ccn_destroy(&ccn);
    exit(status);
}
Example #3
0
int
main(int argc, char **argv)
{

  struct ccn_keystore *keystore = NULL;
  int res = 0;
  struct ccn_charbuf *signed_info = ccn_charbuf_create();
  int i;
  int sec, usec;
  char msgbuf[PAYLOAD_SIZE];
  struct timeval start, end;
  struct ccn_charbuf *message = ccn_charbuf_create();
  struct ccn_charbuf *path = ccn_charbuf_create();
  struct ccn_charbuf *seq = ccn_charbuf_create();

  struct ccn_charbuf *temp = ccn_charbuf_create();
  keystore = ccn_keystore_create();
  ccn_charbuf_putf(temp, "%s/.ccnx/.ccnx_keystore", getenv("HOME"));
  res = ccn_keystore_init(keystore,
			  ccn_charbuf_as_string(temp),
			  "Th1s1sn0t8g00dp8ssw0rd.");
  if (res != 0) {
    printf("Failed to initialize keystore %s\n", ccn_charbuf_as_string(temp));
    exit(1);
  }
  ccn_charbuf_destroy(&temp);
  
  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_DATA,
			       /* freshness */ FRESHNESS,
                               /*finalblockid*/ NULL,
			       /* keylocator */ NULL);

  srandom(time(NULL));
  for (i=0; i<PAYLOAD_SIZE; i++) {
    msgbuf[i] = random();
  }

  printf("Generating %d signed ContentObjects (one . per 100)\n", COUNT);
  gettimeofday(&start, NULL);

  for (i=0; i<COUNT; i++) {
    
    if (i>0 && (i%100) == 0) {
      printf(".");
      fflush(stdout);
    }
    ccn_name_init(path);
    ccn_name_append_str(path, "rtp");
    ccn_name_append_str(path, "protocol");
    ccn_name_append_str(path, "13.2.117.34");
    ccn_name_append_str(path, "domain");
    ccn_name_append_str(path, "smetters");
    ccn_name_append_str(path, "principal");
    ccn_name_append_str(path, "2021915340");
    ccn_name_append_str(path, "id");
    ccn_charbuf_putf(seq, "%u", i);
    ccn_name_append(path, seq->buf, seq->length);
    ccn_name_append_str(path, "seq");
  
    res = ccn_encode_ContentObject(/* out */ message,
				   path, signed_info, 
				   msgbuf, PAYLOAD_SIZE,
				   /* digest_algorithm */ NULL, 
				   ccn_keystore_private_key(keystore));

    ccn_charbuf_reset(message);
    ccn_charbuf_reset(path);
    ccn_charbuf_reset(seq);
  }
  gettimeofday(&end, NULL);
  sec = end.tv_sec - start.tv_sec;
  usec = (int)end.tv_usec - (int)start.tv_usec;
  while (usec < 0) {
    sec--;
    usec += 1000000;
  }

  printf("\nComplete in %d.%06d secs\n", sec, usec);

  return(0);
}
Example #4
0
static const unsigned char *get_my_publisher_key_id() {
    if (cached_keystore == NULL) init_cached_keystore();
    return (ccn_keystore_public_key_digest(cached_keystore));
}
Example #5
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);
}