void doit(void) { gnutls_pkcs12_t pkcs12; gnutls_x509_crt_t client; gnutls_x509_crt_t ca; gnutls_pkcs12_bag_t bag; unsigned char key_id_buf[20]; gnutls_datum_t key_id; int ret, indx; char outbuf[10240]; size_t size; unsigned tests, i; ret = global_init(); if (ret < 0) { fprintf(stderr, "global_init %d", ret); exit(1); } gnutls_global_set_log_function(tls_log_func); if (debug) gnutls_global_set_log_level(4711); /* Read certs. */ ret = gnutls_x509_crt_init(&client); if (ret < 0) { fprintf(stderr, "crt_init: %d", ret); exit(1); } ret = gnutls_x509_crt_import(client, &client_dat, GNUTLS_X509_FMT_PEM); if (ret < 0) { fprintf(stderr, "crt_import: %d", ret); exit(1); } ret = gnutls_x509_crt_init(&ca); if (ret < 0) { fprintf(stderr, "ca_init: %d", ret); exit(1); } ret = gnutls_x509_crt_import(ca, &ca_dat, GNUTLS_X509_FMT_PEM); if (ret < 0) { fprintf(stderr, "ca_import: %d", ret); exit(1); } /* Create PKCS#12 structure. */ ret = gnutls_pkcs12_init(&pkcs12); if (ret < 0) { fprintf(stderr, "pkcs12_init: %d", ret); exit(1); } /* Generate and add PKCS#12 cert bags. */ #ifndef ENABLE_FIPS140 tests = 2; /* include RC2 */ #else tests = 1; #endif for (i = 0; i < tests; i++) { ret = gnutls_pkcs12_bag_init(&bag); if (ret < 0) { fprintf(stderr, "bag_init: %s (%d)\n", gnutls_strerror(ret), ret); exit(1); } ret = gnutls_pkcs12_bag_set_crt(bag, i == 0 ? client : ca); if (ret < 0) { fprintf(stderr, "set_crt: %s (%d)\n", gnutls_strerror(ret), ret); exit(1); } indx = ret; ret = gnutls_pkcs12_bag_set_friendly_name(bag, indx, i == 0 ? "client" : "ca"); if (ret < 0) { fprintf(stderr, "set_friendly_name: %s (%d)\n", gnutls_strerror(ret), ret); exit(1); } size = sizeof(key_id_buf); ret = gnutls_x509_crt_get_key_id(i == 0 ? client : ca, 0, key_id_buf, &size); if (ret < 0) { fprintf(stderr, "get_key_id: %s (%d)\n", gnutls_strerror(ret), ret); exit(1); } key_id.data = key_id_buf; key_id.size = size; ret = gnutls_pkcs12_bag_set_key_id(bag, indx, &key_id); if (ret < 0) { fprintf(stderr, "bag_set_key_id: %s (%d)\n", gnutls_strerror(ret), ret); exit(1); } ret = gnutls_pkcs12_bag_encrypt(bag, "pass", i == 0 ? GNUTLS_PKCS8_USE_PKCS12_3DES : GNUTLS_PKCS_USE_PKCS12_RC2_40); if (ret < 0) { fprintf(stderr, "bag_encrypt: %d: %s", ret, i == 0 ? "3DES" : "RC2-40"); exit(1); } ret = gnutls_pkcs12_set_bag(pkcs12, bag); if (ret < 0) { fprintf(stderr, "set_bag: %s (%d)\n", gnutls_strerror(ret), ret); exit(1); } gnutls_pkcs12_bag_deinit(bag); } /* MAC the structure, export and print. */ ret = gnutls_pkcs12_generate_mac2(pkcs12, GNUTLS_MAC_SHA1, "pass"); if (ret < 0) { fprintf(stderr, "generate_mac: %s (%d)\n", gnutls_strerror(ret), ret); exit(1); } ret = gnutls_pkcs12_verify_mac(pkcs12, "pass"); if (ret < 0) { fprintf(stderr, "verify_mac: %s (%d)\n", gnutls_strerror(ret), ret); exit(1); } ret = gnutls_pkcs12_generate_mac2(pkcs12, GNUTLS_MAC_SHA256, "passwd"); if (ret < 0) { fprintf(stderr, "generate_mac2: %s (%d)\n", gnutls_strerror(ret), ret); exit(1); } ret = gnutls_pkcs12_verify_mac(pkcs12, "passwd"); if (ret < 0) { fprintf(stderr, "verify_mac2: %s (%d)\n", gnutls_strerror(ret), ret); exit(1); } size = sizeof(outbuf); ret = gnutls_pkcs12_export(pkcs12, GNUTLS_X509_FMT_PEM, outbuf, &size); if (ret < 0) { fprintf(stderr, "pkcs12_export: %s (%d)\n", gnutls_strerror(ret), ret); exit(1); } if (debug) fwrite(outbuf, size, 1, stdout); /* Cleanup. */ gnutls_pkcs12_deinit(pkcs12); gnutls_x509_crt_deinit(client); gnutls_x509_crt_deinit(ca); gnutls_global_deinit(); }
/* This function will write a pkcs12 structure into a file. * cert: is a DER encoded certificate * pkcs8_key: is a PKCS #8 encrypted key (note that this must be * encrypted using a PKCS #12 cipher, or some browsers will crash) * password: is the password used to encrypt the PKCS #12 packet. */ int write_pkcs12 (const gnutls_datum_t * cert, const gnutls_datum_t * pkcs8_key, const char *password) { gnutls_pkcs12_t pkcs12; int ret, bag_index; gnutls_pkcs12_bag_t bag, key_bag; char pkcs12_struct[10 * 1024]; size_t pkcs12_struct_size; FILE *fd; /* A good idea might be to use gnutls_x509_privkey_get_key_id() * to obtain a unique ID. */ gnutls_datum_t key_id = { "\x00\x00\x07", 3 }; gnutls_global_init (); /* Firstly we create two helper bags, which hold the certificate, * and the (encrypted) key. */ gnutls_pkcs12_bag_init (&bag); gnutls_pkcs12_bag_init (&key_bag); ret = gnutls_pkcs12_bag_set_data (bag, GNUTLS_BAG_CERTIFICATE, cert); if (ret < 0) { fprintf (stderr, "ret: %s\n", gnutls_strerror (ret)); return 1; } /* ret now holds the bag's index. */ bag_index = ret; /* Associate a friendly name with the given certificate. Used * by browsers. */ gnutls_pkcs12_bag_set_friendly_name (bag, bag_index, "My name"); /* Associate the certificate with the key using a unique key * ID. */ gnutls_pkcs12_bag_set_key_id (bag, bag_index, &key_id); /* use weak encryption for the certificate. */ gnutls_pkcs12_bag_encrypt (bag, password, GNUTLS_PKCS_USE_PKCS12_RC2_40); /* Now the key. */ ret = gnutls_pkcs12_bag_set_data (key_bag, GNUTLS_BAG_PKCS8_ENCRYPTED_KEY, pkcs8_key); if (ret < 0) { fprintf (stderr, "ret: %s\n", gnutls_strerror (ret)); return 1; } /* Note that since the PKCS #8 key is already encrypted we don't * bother encrypting that bag. */ bag_index = ret; gnutls_pkcs12_bag_set_friendly_name (key_bag, bag_index, "My name"); gnutls_pkcs12_bag_set_key_id (key_bag, bag_index, &key_id); /* The bags were filled. Now create the PKCS #12 structure. */ gnutls_pkcs12_init (&pkcs12); /* Insert the two bags in the PKCS #12 structure. */ gnutls_pkcs12_set_bag (pkcs12, bag); gnutls_pkcs12_set_bag (pkcs12, key_bag); /* Generate a message authentication code for the PKCS #12 * structure. */ gnutls_pkcs12_generate_mac (pkcs12, password); pkcs12_struct_size = sizeof (pkcs12_struct); ret = gnutls_pkcs12_export (pkcs12, GNUTLS_X509_FMT_DER, pkcs12_struct, &pkcs12_struct_size); if (ret < 0) { fprintf (stderr, "ret: %s\n", gnutls_strerror (ret)); return 1; } fd = fopen (OUTFILE, "w"); if (fd == NULL) { fprintf (stderr, "cannot open file\n"); return 1; } fwrite (pkcs12_struct, 1, pkcs12_struct_size, fd); fclose (fd); gnutls_pkcs12_bag_deinit (bag); gnutls_pkcs12_bag_deinit (key_bag); gnutls_pkcs12_deinit (pkcs12); return 0; }