void PublicKey::unpack(Blob::const_iterator& begin, Blob::const_iterator& end) { Blob tmp = deserialize<Blob>(begin, end); if (pk) gnutls_pubkey_deinit(pk); gnutls_pubkey_init(&pk); const gnutls_datum_t dat {(uint8_t*)tmp.data(), (unsigned)tmp.size()}; int err = gnutls_pubkey_import(pk, &dat, GNUTLS_X509_FMT_PEM); if (err != GNUTLS_E_SUCCESS) err = gnutls_pubkey_import(pk, &dat, GNUTLS_X509_FMT_DER); if (err != GNUTLS_E_SUCCESS) throw CryptoException(std::string("Could not read public key: ") + gnutls_strerror(err)); }
/* Load a public key. * @mand should be non zero if it is required to read a public key. */ gnutls_pubkey_t load_pubkey(int mand, common_info_st * info) { gnutls_pubkey_t key; int ret; gnutls_datum_t dat; size_t size; if (!info->pubkey && !mand) return NULL; if (info->pubkey == NULL) { fprintf(stderr, "missing --load-pubkey\n"); exit(1); } if (gnutls_url_is_supported(info->pubkey) != 0) return _load_url_pubkey(info->pubkey); ret = gnutls_pubkey_init(&key); if (ret < 0) { fprintf(stderr, "privkey_init: %s\n", gnutls_strerror(ret)); exit(1); } dat.data = (void *) read_binary_file(info->pubkey, &size); dat.size = size; if (!dat.data) { fprintf(stderr, "reading --load-pubkey: %s\n", info->pubkey); exit(1); } ret = gnutls_pubkey_import(key, &dat, info->incert_format); free(dat.data); if (ret == GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR) { fprintf(stderr, "import error: could not find a valid PEM header; " "check if your key has the PUBLIC KEY header\n"); exit(1); } if (ret < 0) { fprintf(stderr, "importing --load-pubkey: %s: %s\n", info->pubkey, gnutls_strerror(ret)); exit(1); } return key; }
/* Load a public key. * @mand should be non zero if it is required to read a public key. */ gnutls_pubkey_t load_pubkey (int mand, common_info_st * info) { gnutls_pubkey_t key; int ret; gnutls_datum_t dat; size_t size; if (!info->pubkey && !mand) return NULL; if (info->pubkey == NULL) error (EXIT_FAILURE, 0, "missing --load-pubkey"); #ifdef ENABLE_PKCS11 if (strncmp(info->pubkey, "pkcs11:", 7) == 0) return _load_pkcs11_pubkey(info->pubkey); #endif ret = gnutls_pubkey_init (&key); if (ret < 0) error (EXIT_FAILURE, 0, "privkey_init: %s", gnutls_strerror (ret)); dat.data = read_binary_file (info->pubkey, &size); dat.size = size; if (!dat.data) error (EXIT_FAILURE, errno, "reading --load-pubkey: %s", info->pubkey); ret = gnutls_pubkey_import (key, &dat, info->incert_format); free (dat.data); if (ret == GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR) { error (EXIT_FAILURE, 0, "import error: could not find a valid PEM header; " "check if your key has the PUBLIC KEY header"); } if (ret < 0) error (EXIT_FAILURE, 0, "importing --load-pubkey: %s: %s", info->pubkey, gnutls_strerror (ret)); return key; }
int main(int argc, char *argv[]) { int ret = 1; int i; gnutls_pubkey_t pubkey = NULL; gnutls_x509_privkey_t sigkey = NULL; gnutls_x509_crt_t sigcert = NULL; gnutls_x509_crt_t crt = NULL; const char *pubkey_filename = NULL; const char *sigkey_filename = NULL; const char *cert_filename = NULL; const char *modulus_str = NULL; const char *issuercert_filename = NULL; unsigned char *modulus_bin = NULL; int modulus_len = 0; gnutls_datum_t datum = { NULL, 0}, out = { NULL, 0}; int serial = 1; time_t now; int err; FILE *cert_file; char *subject = NULL; const char *error = NULL; int days = 365; char *sigkeypass = NULL; uint32_t ser_number; long int exponent = 0x10001; bool write_pem = false; uint8_t id[512]; size_t id_size = sizeof(id); enum cert_type_t certtype = CERT_TYPE_EK; const char *oid; unsigned int key_usage; char *tpm_manufacturer = NULL; char *tpm_version = NULL; char *tpm_model = NULL; char *platf_manufacturer = NULL; char *platf_version = NULL; char *platf_model = NULL; i = 1; while (i < argc) { if (!strcmp(argv[i], "--pubkey")) { i++; if (i == argc) { fprintf(stderr, "Missing argument for --pubkey.\n"); goto cleanup; } pubkey_filename = argv[i]; } else if (!strcmp(argv[i], "--modulus")) { i++; if (i == argc) { fprintf(stderr, "Missing argument for --modulus.\n"); goto cleanup; } modulus_str = argv[i]; if (!(modulus_bin = hex_str_to_bin(modulus_str, &modulus_len))) { goto cleanup; } } else if (!strcmp(argv[i], "--exponent")) { i++; if (i == argc) { fprintf(stderr, "Missing argument for --exponent.\n"); goto cleanup; } exponent = strtol(argv[i], NULL, 0); if (exponent == 0) { fprintf(stderr, "Exponent is wrong and cannot be 0.\n"); goto cleanup; } if (exponent > UINT_MAX) { fprintf(stderr, "Exponent must fit into 32bits.\n"); goto cleanup; } } else if (!strcmp(argv[i], "--signkey")) { i++; if (i == argc) { fprintf(stderr, "Missing argument for --signkey.\n"); goto cleanup; } sigkey_filename = argv[i]; } else if (!strcmp(argv[i], "--signkey-password")) { i++; if (i == argc) { fprintf(stderr, "Missing argument for --signkey-password.\n"); goto cleanup; } sigkeypass = argv[i]; } else if (!strcmp(argv[i], "--issuercert")) { i++; if (i == argc) { fprintf(stderr, "Missing argument for --issuercert.\n"); goto cleanup; } issuercert_filename = argv[i]; } else if (!strcmp(argv[i], "--out-cert")) { i++; if (i == argc) { fprintf(stderr, "Missing argument for --out-cert.\n"); goto cleanup; } cert_filename = argv[i]; } else if (!strcmp(argv[i], "--subject")) { i++; if (i == argc) { fprintf(stderr, "Missing argument for --subject.\n"); goto cleanup; } subject = argv[i]; } else if (!strcmp(argv[i], "--days")) { i++; if (i == argc) { fprintf(stderr, "Missing argument for --days.\n"); goto cleanup; } days = atoi(argv[i]); } else if (!strcmp(argv[i], "--serial")) { i++; if (i == argc) { fprintf(stderr, "Missing argument for --serial.\n"); goto cleanup; } serial = atoi(argv[i]); } else if (!strcmp(argv[i], "--type")) { i++; if (i == argc) { fprintf(stderr, "Missing argument for --type.\n"); goto cleanup; } if (!strcasecmp(argv[i], "ek")) { certtype = CERT_TYPE_EK; } else if (!strcasecmp(argv[i], "platform")) { certtype = CERT_TYPE_PLATFORM; // } else if (!strcasecmp(argv[i], "aik")) { // /* AIK cert needs EK cert as input */ // certtype = CERT_TYPE_AIK; } else { fprintf(stderr, "Unknown certificate type '%s'.\n", argv[i]); goto cleanup; } } else if (!strcmp(argv[i], "--tpm-manufacturer")) { i++; if (i == argc) { fprintf(stderr, "Missing argument for --tpm-manufacturer.\n"); goto cleanup; } tpm_manufacturer = argv[i]; } else if (!strcmp(argv[i], "--tpm-model")) { i++; if (i == argc) { fprintf(stderr, "Missing argument for --tpm-model.\n"); goto cleanup; } tpm_model = argv[i]; } else if (!strcmp(argv[i], "--tpm-version")) { i++; if (i == argc) { fprintf(stderr, "Missing argument for --tpm-version.\n"); goto cleanup; } tpm_version = argv[i]; } else if (!strcmp(argv[i], "--platform-manufacturer")) { i++; if (i == argc) { fprintf(stderr, "Missing argument for --platform-manufacturer.\n"); goto cleanup; } platf_manufacturer = argv[i]; } else if (!strcmp(argv[i], "--platform-model")) { i++; if (i == argc) { fprintf(stderr, "Missing argument for --platform-model.\n"); goto cleanup; } platf_model = argv[i]; } else if (!strcmp(argv[i], "--platform-version")) { i++; if (i == argc) { fprintf(stderr, "Missing argument for --platform-version.\n"); goto cleanup; } platf_version = argv[i]; } else if (!strcmp(argv[i], "--pem")) { write_pem = true; } else if (!strcmp(argv[i], "--help")) { usage(argv[0]); exit(0); } else { fprintf(stderr, "Unknown command line parameter '%s'.\n", argv[i]); usage(argv[0]); exit(1); } i++; } ser_number = htonl(serial); if (pubkey_filename == NULL && modulus_bin == NULL) { fprintf(stderr, "Missing public EK file and modulus.\n"); usage(argv[0]); goto cleanup; } if (issuercert_filename == NULL) { fprintf(stderr, "The issuer certificate name is required.\n"); goto cleanup; } switch (certtype) { case CERT_TYPE_EK: case CERT_TYPE_PLATFORM: if (tpm_manufacturer == NULL || tpm_model == NULL || tpm_version == NULL) { fprintf(stderr, "--tpm-manufacturer and --tpm-model and " "--tpm version " "must all be provided\n"); goto cleanup; } break; case CERT_TYPE_AIK: break; } switch (certtype) { case CERT_TYPE_PLATFORM: if (platf_manufacturer == NULL || platf_model == NULL || platf_version == NULL) { fprintf(stderr, "--platform-manufacturer and --platform-model and " "--platform version " "must all be provided\n"); goto cleanup; } break; case CERT_TYPE_EK: case CERT_TYPE_AIK: break; } err = gnutls_global_init(); if (err < 0) { fprintf(stderr, "gnutls_global_init failed.\n"); goto cleanup; } gnutls_x509_privkey_init(&sigkey); if (pubkey_filename) { gnutls_pubkey_init(&pubkey); err = gnutls_load_file(pubkey_filename, &datum); if (err != GNUTLS_E_SUCCESS) { fprintf(stderr, "Could not open file for EK public key: %s\n", strerror(errno)); goto cleanup; } err = gnutls_pubkey_import(pubkey, &datum, GNUTLS_X509_FMT_PEM); gnutls_free(datum.data); datum.data = NULL; if (err != GNUTLS_E_SUCCESS) { fprintf(stderr, "Could not import EK.\n"); goto cleanup; } } else { pubkey = create_rsa_from_modulus(modulus_bin, modulus_len, exponent); free(modulus_bin); modulus_bin = NULL; if (pubkey == NULL) goto cleanup; } /* all types of keys must have pubkey set now otherwise the signing will not work */ if (sigkey_filename == NULL) { fprintf(stderr, "Missing signature key.\n"); usage(argv[0]); exit(1); } #define CHECK_GNUTLS_ERROR(_err, _msg, ...) \ if (_err != GNUTLS_E_SUCCESS) { \ fprintf(stderr, _msg, __VA_ARGS__); \ goto cleanup; \ } err = gnutls_load_file(sigkey_filename, &datum); CHECK_GNUTLS_ERROR(err, "Could not read signing key from file %s: %s\n", sigkey_filename, gnutls_strerror(err)); if (sigkeypass) { err = gnutls_x509_privkey_import2(sigkey, &datum, GNUTLS_X509_FMT_PEM, sigkeypass, 0); } else { err = gnutls_x509_privkey_import(sigkey, &datum, GNUTLS_X509_FMT_PEM); } gnutls_free(datum.data); datum.data = NULL; CHECK_GNUTLS_ERROR(err, "Could not import signing key : %s\n", gnutls_strerror(err)); err = gnutls_load_file(issuercert_filename, &datum); CHECK_GNUTLS_ERROR(err, "Could not read certificate from file %s : %s\n", issuercert_filename, gnutls_strerror(err)); gnutls_x509_crt_init(&sigcert); err = gnutls_x509_crt_import(sigcert, &datum, GNUTLS_X509_FMT_PEM); gnutls_free(datum.data); datum.data = NULL; CHECK_GNUTLS_ERROR(err, "Could not import issuer certificate: %s\n", gnutls_strerror(err)); err = gnutls_x509_crt_init(&crt); CHECK_GNUTLS_ERROR(err, "CRT init failed: %s\n", gnutls_strerror(err)) /* 3.5.1 Version */ err = gnutls_x509_crt_set_version(crt, 3); CHECK_GNUTLS_ERROR(err, "Could not set version on CRT: %s\n", gnutls_strerror(err)) /* 3.5.2 Serial Number */ err = gnutls_x509_crt_set_serial(crt, &ser_number, sizeof(ser_number)); CHECK_GNUTLS_ERROR(err, "Could not set serial on CRT: %s\n", gnutls_strerror(err)) /* 3.5.5 Validity */ now = time(NULL); err = gnutls_x509_crt_set_activation_time(crt, now); CHECK_GNUTLS_ERROR(err, "Could not set activation time on CRT: %s\n", gnutls_strerror(err)) err = gnutls_x509_crt_set_expiration_time(crt, now + (time_t)days * 24 * 60 * 60); CHECK_GNUTLS_ERROR(err, "Could not set expiration time on CRT: %s\n", gnutls_strerror(err)) /* 3.5.6 Subject -- should be empty, but we allow it anyway */ if (subject) { err = gnutls_x509_crt_set_dn(crt, subject, &error); CHECK_GNUTLS_ERROR(err, "Could not set DN on CRT: %s\n" "DN '%s must be fault after %s\n.'", gnutls_strerror(err), subject, error) } /* 3.5.7 Public Key Info */ switch (certtype) { case CERT_TYPE_EK: oid = "1.2.840.113549.1.1.7"; break; case CERT_TYPE_PLATFORM: oid = NULL; break; case CERT_TYPE_AIK: oid = "1.2.840.113549.1.1.1"; break; default: fprintf(stderr, "Internal error: unhandle case in line %d\n", __LINE__); goto cleanup; } if (oid) { err = gnutls_x509_crt_set_key_purpose_oid(crt, oid, 0); CHECK_GNUTLS_ERROR(err, "Could not set key purpose on CRT: %s\n", gnutls_strerror(err)) } /* 3.5.8 Certificate Policies -- skip since not mandated */ /* 3.5.9 Subject Alternative Names -- missing code */ err = create_tpm_manufacturer_info(tpm_manufacturer, tpm_model, tpm_version, &datum); if (!err && datum.size > 0) { /* * GNUTLS's write_new_general_name can only handle a few GNUTLS_SAN_* * -> we have to use GNUTLS_SAN_URI */ err = gnutls_x509_crt_set_subject_alt_name(crt, GNUTLS_SAN_URI, datum.data, datum.size, GNUTLS_FSAN_SET); CHECK_GNUTLS_ERROR(err, "Could not set subject alt name: %s\n", gnutls_strerror(err)) }