/** * Generates a unique fingerprint of the pkcs10 request * by computing an MD5 hash over it */ chunk_t scep_generate_pkcs10_fingerprint(chunk_t pkcs10) { chunk_t digest = chunk_alloca(HASH_SIZE_MD5); hasher_t *hasher; hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5); hasher->get_hash(hasher, pkcs10, digest.ptr); hasher->destroy(hasher); return chunk_to_hex(digest, NULL, FALSE); }
/** * write back the last serial number to file */ static void write_serial(chunk_t serial) { FILE *fd = fopen(OPENAC_SERIAL, "w"); if (fd) { chunk_t hex_serial; DBG1(DBG_LIB, " serial number is %#B", &serial); hex_serial = chunk_to_hex(serial, NULL, FALSE); fprintf(fd, "%.*s\n", (int)hex_serial.len, hex_serial.ptr); fclose(fd); free(hex_serial.ptr); } else { DBG1(DBG_LIB, " could not open file '%s' for writing", OPENAC_SERIAL); } }
/** * Generate a transaction id as the MD5 hash of an public key * the transaction id is also used as a unique serial number */ void scep_generate_transaction_id(public_key_t *key, chunk_t *transID, chunk_t *serialNumber) { chunk_t digest = chunk_alloca(HASH_SIZE_MD5); chunk_t keyEncoding = chunk_empty, keyInfo; hasher_t *hasher; bool msb_set; u_char *pos; key->get_encoding(key, PUBKEY_ASN1_DER, &keyEncoding); keyInfo = asn1_wrap(ASN1_SEQUENCE, "mm", asn1_algorithmIdentifier(OID_RSA_ENCRYPTION), asn1_bitstring("m", keyEncoding)); hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5); if (!hasher || !hasher->get_hash(hasher, keyInfo, digest.ptr)) { memset(digest.ptr, 0, digest.len); } DESTROY_IF(hasher); free(keyInfo.ptr); /* is the most significant bit of the digest set? */ msb_set = (*digest.ptr & 0x80) == 0x80; /* allocate space for the serialNumber */ serialNumber->len = msb_set + digest.len; serialNumber->ptr = malloc(serialNumber->len); /* the serial number as the two's complement of the digest */ pos = serialNumber->ptr; if (msb_set) { *pos++ = 0x00; } memcpy(pos, digest.ptr, digest.len); /* the transaction id is the serial number in hex format */ *transID = chunk_to_hex(digest, NULL, TRUE); }
bool imv_attestation_process(pa_tnc_attr_t *attr, imv_msg_t *out_msg, imv_state_t *state, pts_meas_algorithms_t supported_algorithms, pts_dh_group_t supported_dh_groups, pts_database_t *pts_db, credential_manager_t *pts_credmgr) { imv_session_t *session; imv_attestation_state_t *attestation_state; pen_type_t attr_type; pts_t *pts; session = state->get_session(state); attestation_state = (imv_attestation_state_t*)state; pts = attestation_state->get_pts(attestation_state); attr_type = attr->get_type(attr); switch (attr_type.type) { case TCG_PTS_PROTO_CAPS: { tcg_pts_attr_proto_caps_t *attr_cast; pts_proto_caps_flag_t flags; attr_cast = (tcg_pts_attr_proto_caps_t*)attr; flags = attr_cast->get_flags(attr_cast); pts->set_proto_caps(pts, flags); break; } case TCG_PTS_MEAS_ALGO_SELECTION: { tcg_pts_attr_meas_algo_t *attr_cast; pts_meas_algorithms_t selected_algorithm; attr_cast = (tcg_pts_attr_meas_algo_t*)attr; selected_algorithm = attr_cast->get_algorithms(attr_cast); if (!(selected_algorithm & supported_algorithms)) { DBG1(DBG_IMV, "PTS-IMC selected unsupported" " measurement algorithm"); return FALSE; } pts->set_meas_algorithm(pts, selected_algorithm); state->set_action_flags(state, IMV_ATTESTATION_ALGO); break; } case TCG_PTS_DH_NONCE_PARAMS_RESP: { tcg_pts_attr_dh_nonce_params_resp_t *attr_cast; int nonce_len, min_nonce_len; pts_dh_group_t dh_group; pts_meas_algorithms_t offered_algorithms, selected_algorithm; chunk_t responder_value, responder_nonce; attr_cast = (tcg_pts_attr_dh_nonce_params_resp_t*)attr; responder_nonce = attr_cast->get_responder_nonce(attr_cast); /* check compliance of responder nonce length */ min_nonce_len = lib->settings->get_int(lib->settings, "%s.plugins.imv-attestation.min_nonce_len", 0, lib->ns); nonce_len = responder_nonce.len; if (nonce_len < PTS_MIN_NONCE_LEN || (min_nonce_len > 0 && nonce_len < min_nonce_len)) { attr = pts_dh_nonce_error_create( max(PTS_MIN_NONCE_LEN, min_nonce_len), PTS_MAX_NONCE_LEN); out_msg->add_attribute(out_msg, attr); break; } dh_group = attr_cast->get_dh_group(attr_cast); if (!(dh_group & supported_dh_groups)) { DBG1(DBG_IMV, "PTS-IMC selected unsupported DH group"); return FALSE; } offered_algorithms = attr_cast->get_hash_algo_set(attr_cast); selected_algorithm = pts_meas_algo_select(supported_algorithms, offered_algorithms); if (selected_algorithm == PTS_MEAS_ALGO_NONE) { attr = pts_hash_alg_error_create(supported_algorithms); out_msg->add_attribute(out_msg, attr); break; } pts->set_dh_hash_algorithm(pts, selected_algorithm); if (!pts->create_dh_nonce(pts, dh_group, nonce_len)) { return FALSE; } responder_value = attr_cast->get_responder_value(attr_cast); pts->set_peer_public_value(pts, responder_value, responder_nonce); /* Calculate secret assessment value */ if (!pts->calculate_secret(pts)) { return FALSE; } state->set_action_flags(state, IMV_ATTESTATION_DH_NONCE); break; } case TCG_PTS_TPM_VERSION_INFO: { tcg_pts_attr_tpm_version_info_t *attr_cast; chunk_t tpm_version_info; attr_cast = (tcg_pts_attr_tpm_version_info_t*)attr; tpm_version_info = attr_cast->get_tpm_version_info(attr_cast); pts->set_tpm_version_info(pts, tpm_version_info); break; } case TCG_PTS_AIK: { tcg_pts_attr_aik_t *attr_cast; certificate_t *aik, *issuer; public_key_t *public; chunk_t keyid, keyid_hex, device_id; int aik_id; enumerator_t *e; bool trusted = FALSE, trusted_chain = FALSE; attr_cast = (tcg_pts_attr_aik_t*)attr; aik = attr_cast->get_aik(attr_cast); if (!aik) { DBG1(DBG_IMV, "AIK unavailable"); attestation_state->set_measurement_error(attestation_state, IMV_ATTESTATION_ERROR_NO_TRUSTED_AIK); break; } /* check trust into public key as stored in the database */ public = aik->get_public_key(aik); public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, &keyid); DBG1(DBG_IMV, "verifying AIK with keyid %#B", &keyid); keyid_hex = chunk_to_hex(keyid, NULL, FALSE); if (session->get_device_id(session, &device_id) && chunk_equals(keyid_hex, device_id)) { trusted = session->get_device_trust(session); } else { DBG1(DBG_IMV, "device ID unknown or different from AIK keyid"); } DBG1(DBG_IMV, "AIK public key is %strusted", trusted ? "" : "not "); public->destroy(public);
/** * Add ITA Device ID attribute to the send queue */ static void add_device_id(imc_msg_t *msg) { pa_tnc_attr_t *attr; chunk_t value = chunk_empty, keyid; char *name, *device_id, *cert_path; certificate_t *cert = NULL; public_key_t *pubkey; /* Get the device ID as a character string */ device_id = lib->settings->get_str(lib->settings, "%s.plugins.imc-os.device_id", NULL, lib->ns); if (device_id) { value = chunk_clone(chunk_from_str(device_id)); } if (value.len == 0) { /* Derive the device ID from a raw public key */ cert_path = lib->settings->get_str(lib->settings, "%s.plugins.imc-os.device_pubkey", NULL, lib->ns); if (cert_path) { cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_TRUSTED_PUBKEY, BUILD_FROM_FILE, cert_path, BUILD_END); if (cert) { DBG2(DBG_IMC, "loaded device public key from '%s'", cert_path); } else { DBG1(DBG_IMC, "loading device public key from '%s' failed", cert_path); } } if (!cert) { /* Derive the device ID from the public key contained in a certificate */ cert_path = lib->settings->get_str(lib->settings, "%s.plugins.imc-os.device_cert", NULL, lib->ns); if (cert_path) { cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, BUILD_FROM_FILE, cert_path, BUILD_END); if (cert) { DBG2(DBG_IMC, "loaded device certificate from '%s'", cert_path); } else { DBG1(DBG_IMC, "loading device certificate from '%s' failed", cert_path); } } } /* Compute the SHA-1 keyid of the retrieved device public key */ if (cert) { pubkey = cert->get_public_key(cert); if (pubkey) { if (pubkey->get_fingerprint(pubkey, KEYID_PUBKEY_INFO_SHA1, &keyid)) { value = chunk_to_hex(keyid, NULL, FALSE); } pubkey->destroy(pubkey); } cert->destroy(cert); } } if (value.len == 0) { /* Derive the device ID from some unique OS settings */ name = os->get_type(os) == OS_TYPE_ANDROID ? "android_id" : "/var/lib/dbus/machine-id"; value = os->get_setting(os, name); /* Trim trailing newline character */ if (value.len > 0 && value.ptr[value.len - 1] == '\n') { value.len--; } } if (value.len == 0) { DBG1(DBG_IMC, "no device ID available"); return; } DBG1(DBG_IMC, "device ID is %.*s", value.len, value.ptr); attr = ita_attr_device_id_create(value); msg->add_attribute(msg, attr); free(value.ptr); }
/** * Extract subject DN */ static int dn() { identification_t *id; certificate_t *cert; chunk_t chunk; enum { FORMAT_CONFIG, FORMAT_HEX, FORMAT_BASE64, FORMAT_BINARY, } format = FORMAT_CONFIG; char *arg, *file = NULL, *fmt; while (TRUE) { switch (command_getopt(&arg)) { case 'h': return command_usage(NULL); case 'f': if (streq(arg, "hex")) { format = FORMAT_HEX; } else if (streq(arg, "base64")) { format = FORMAT_BASE64; } else if (streq(arg, "bin")) { format = FORMAT_BINARY; } else if (!streq(arg, "config")) { return command_usage( "invalid output format"); } continue; case 'i': file = arg; continue; case EOF: break; default: return command_usage("invalid --print option"); } break; } if (file) { cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, BUILD_FROM_FILE, file, BUILD_END); } else { chunk_t chunk; set_file_mode(stdin, CERT_ASN1_DER); if (!chunk_from_fd(0, &chunk)) { fprintf(stderr, "reading input failed: %s\n", strerror(errno)); return 1; } cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, BUILD_BLOB, chunk, BUILD_END); free(chunk.ptr); } if (!cert) { fprintf(stderr, "parsing input failed\n"); return 1; } id = cert->get_subject(cert); if (!id) { fprintf(stderr, "failed to get certificate's subject DN\n"); cert->destroy(cert); return 1; } fmt = "%.*s\n"; switch (format) { case FORMAT_CONFIG: fmt = "\"asn1dn:#%.*s\"\n"; /* fall-through */ case FORMAT_HEX: chunk = chunk_to_hex(id->get_encoding(id), NULL, FALSE); printf(fmt, (int)chunk.len, chunk.ptr); chunk_free(&chunk); break; case FORMAT_BASE64: chunk = chunk_to_base64(id->get_encoding(id), NULL); printf(fmt, (int)chunk.len, chunk.ptr); chunk_free(&chunk); break; case FORMAT_BINARY: chunk = id->get_encoding(id); if (fwrite(chunk.ptr, chunk.len, 1, stdout) != 1) { fprintf(stderr, "writing subject DN failed\n"); } break; } cert->destroy(cert); return 0; }
END_TEST /******************************************************************************* * BASE16 encoding test */ START_TEST(test_base16) { /* test vectors from RFC 4648: * * BASE16("") = "" * BASE16("f") = "66" * BASE16("fo") = "666F" * BASE16("foo") = "666F6F" * BASE16("foob") = "666F6F62" * BASE16("fooba") = "666F6F6261" * BASE16("foobar") = "666F6F626172" */ typedef struct { bool upper; char *in; char *out; } testdata_t; testdata_t test[] = { {TRUE, "", ""}, {TRUE, "f", "66"}, {TRUE, "fo", "666F"}, {TRUE, "foo", "666F6F"}, {TRUE, "foob", "666F6F62"}, {TRUE, "fooba", "666F6F6261"}, {TRUE, "foobar", "666F6F626172"}, {FALSE, "", ""}, {FALSE, "f", "66"}, {FALSE, "fo", "666f"}, {FALSE, "foo", "666f6f"}, {FALSE, "foob", "666f6f62"}, {FALSE, "fooba", "666f6f6261"}, {FALSE, "foobar", "666f6f626172"}, }; testdata_t test_colon[] = { {TRUE, "", ""}, {TRUE, "f", "66"}, {TRUE, "fo", "66:6F"}, {TRUE, "foo", "66:6F:6F"}, {FALSE, "foob", "66:6f:6f:62"}, {FALSE, "fooba", "66:6f:6f:62:61"}, {FALSE, "foobar", "66:6f:6f:62:61:72"}, {FALSE, "foobar", "66:6f6f:6261:72"}, }; int i; for (i = 0; i < countof(test); i++) { chunk_t out; out = chunk_to_hex(chunk_create(test[i].in, strlen(test[i].in)), NULL, test[i].upper); ck_assert_str_eq(out.ptr, test[i].out); free(out.ptr); } for (i = 0; i < countof(test); i++) { chunk_t out; out = chunk_from_hex(chunk_create(test[i].out, strlen(test[i].out)), NULL); fail_unless(strneq(out.ptr, test[i].in, out.len), "base16 conversion error - should '%s', is %#B", test[i].in, &out); free(out.ptr); } for (i = 0; i < countof(test_colon); i++) { chunk_t out; out = chunk_from_hex(chunk_create(test_colon[i].out, strlen(test_colon[i].out)), NULL); fail_unless(strneq(out.ptr, test_colon[i].in, out.len), "base16 conversion error - should '%s', is %#B", test_colon[i].in, &out); free(out.ptr); } }