/** * Load certificate distribution points */ static void load_cdps(settings_t *settings) { enumerator_t *enumerator; identification_t *id; char *ca, *uri, *section; certificate_type_t type; x509_t *x509; enumerator = settings->create_section_enumerator(settings, "cdps"); while (enumerator->enumerate(enumerator, §ion)) { if (strncaseeq(section, "crl", strlen("crl"))) { type = CERT_X509_CRL; } else if (strncaseeq(section, "ocsp", strlen("ocsp"))) { type = CERT_X509_OCSP_RESPONSE; } else { fprintf(stderr, "unknown cdp type '%s', ignored\n", section); continue; } uri = settings->get_str(settings, "cdps.%s.uri", NULL, section); ca = settings->get_str(settings, "cdps.%s.ca", NULL, section); if (!ca || !uri) { fprintf(stderr, "cdp '%s' misses ca/uri, ignored\n", section); continue; } x509 = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, BUILD_FROM_FILE, ca, BUILD_END); if (!x509) { fprintf(stderr, "loading cdp '%s' ca failed, ignored\n", section); continue; } id = identification_create_from_encoding(ID_KEY_ID, x509->get_subjectKeyIdentifier(x509)); conftest->creds->add_cdp(conftest->creds, type, id, uri); DESTROY_IF((certificate_t*)x509); id->destroy(id); } enumerator->destroy(enumerator); }
/** * Check, as client, if we have a client certificate with private key */ static identification_t *find_client_id() { identification_t *client = NULL, *keyid; enumerator_t *enumerator; certificate_t *cert; public_key_t *pubkey; private_key_t *privkey; chunk_t chunk; enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr, CERT_X509, KEY_ANY, NULL, FALSE); while (enumerator->enumerate(enumerator, &cert)) { pubkey = cert->get_public_key(cert); if (pubkey) { if (pubkey->get_fingerprint(pubkey, KEYID_PUBKEY_SHA1, &chunk)) { keyid = identification_create_from_encoding(ID_KEY_ID, chunk); privkey = lib->credmgr->get_private(lib->credmgr, pubkey->get_type(pubkey), keyid, NULL); keyid->destroy(keyid); if (privkey) { client = cert->get_subject(cert); client = client->clone(client); privkey->destroy(privkey); } } pubkey->destroy(pubkey); } if (client) { break; } } enumerator->destroy(enumerator); return client; }
/** * ipsec pool --statusattr - show all attribute entries */ void status_attr(bool hexout) { configuration_attribute_type_t type; value_type_t value_type; chunk_t value, addr_chunk, mask_chunk, identity_chunk; identification_t *identity; enumerator_t *enumerator; host_t *addr, *mask; char type_name[30]; bool first = TRUE; int i, identity_type; char *pool_name; /* enumerate over all attributes */ enumerator = db->query(db, "SELECT attributes.type, attribute_pools.name, " "identities.type, identities.data, attributes.value " "FROM attributes " "LEFT OUTER JOIN identities " "ON attributes.identity = identities.id " "LEFT OUTER JOIN attribute_pools " "ON attributes.pool = attribute_pools.id " "ORDER BY attributes.type, attribute_pools.name, " "identities.type, identities.data, attributes.value", DB_INT, DB_TEXT, DB_INT, DB_BLOB, DB_BLOB); if (enumerator) { while (enumerator->enumerate(enumerator, &type,&pool_name, &identity_type, &identity_chunk, &value)) { if (first) { printf(" type description pool " " identity value\n"); first = FALSE; } snprintf(type_name, sizeof(type_name), "%N", configuration_attribute_type_names, type); if (type_name[0] == '(') { type_name[0] = '\0'; } printf("%5d %-20s ",type, type_name); printf(" %-10s ", (pool_name ? pool_name : "")); if (identity_type) { identity = identification_create_from_encoding(identity_type, identity_chunk); printf(" %-20.20Y ", identity); identity->destroy(identity); } else { printf(" "); } value_type = VALUE_HEX; if (!hexout) { for (i = 0; i < countof(attr_info); i++) { if (type == attr_info[i].type) { value_type = attr_info[i].value_type; break; } } } switch (value_type) { case VALUE_ADDR: addr = host_create_from_chunk(AF_UNSPEC, value, 0); if (addr) { printf(" %H\n", addr); addr->destroy(addr); } else { /* value cannot be represented as an IP address */ printf(" %#B\n", &value); } break; case VALUE_SUBNET: if (value.len % UNITY_NETWORK_LEN == 0) { for (i = 0; i < value.len / UNITY_NETWORK_LEN; i++) { addr_chunk = chunk_create(value.ptr + i*UNITY_NETWORK_LEN, 4); addr = host_create_from_chunk(AF_INET, addr_chunk, 0); mask_chunk = chunk_create(addr_chunk.ptr + 4, 4); mask = host_create_from_chunk(AF_INET, mask_chunk, 0); printf("%s%H/%H", (i > 0) ? "," : " ", addr, mask); addr->destroy(addr); mask->destroy(mask); } printf("\n"); } else { /* value cannot be represented as a list of subnets */ printf(" %#B\n", &value); } break; case VALUE_STRING: printf("\"%.*s\"\n", (int)value.len, value.ptr); break; case VALUE_HEX: default: printf(" %#B\n", &value); } } enumerator->destroy(enumerator); } }
/** * ipsec pool --leases - show lease information of a pool */ static void leases(char *filter, bool utc) { enumerator_t *query; array_t *to_free = NULL; chunk_t address_chunk, identity_chunk; int identity_type; char *name; u_int db_acquired, db_released, db_timeout; time_t acquired, released, timeout; host_t *address; identification_t *identity; bool found = FALSE; query = create_lease_query(filter, &to_free); if (!query) { fprintf(stderr, "querying leases failed.\n"); exit(EXIT_FAILURE); } while (query->enumerate(query, &name, &address_chunk, &identity_type, &identity_chunk, &db_acquired, &db_released, &db_timeout)) { if (!found) { int len = utc ? 25 : 21; found = TRUE; printf("%-8s %-15s %-7s %-*s %-*s %s\n", "name", "address", "status", len, "start", len, "end", "identity"); } address = host_create_from_chunk(AF_UNSPEC, address_chunk, 0); identity = identification_create_from_encoding(identity_type, identity_chunk); /* u_int is not always equal to time_t */ acquired = (time_t)db_acquired; released = (time_t)db_released; timeout = (time_t)db_timeout; printf("%-8s %-15H ", name, address); if (released == 0) { printf("%-7s ", "online"); } else if (timeout == 0) { printf("%-7s ", "static"); } else if (released >= time(NULL) - timeout) { printf("%-7s ", "valid"); } else { printf("%-7s ", "expired"); } printf(" %T ", &acquired, utc); if (released) { printf("%T ", &released, utc); } else { printf(" "); if (utc) { printf(" "); } } printf("%Y\n", identity); DESTROY_IF(address); identity->destroy(identity); } query->destroy(query); if (to_free) { array_destroy_function(to_free, (void*)free, NULL); } if (!found) { fprintf(stderr, "no matching leases found.\n"); exit(EXIT_FAILURE); } }
/** * Parse a PKCS#7 envelopedData object */ bool pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data, chunk_t serialNumber, private_key_t *key) { asn1_parser_t *parser; chunk_t object; chunk_t iv = chunk_empty; chunk_t symmetric_key = chunk_empty; chunk_t encrypted_content = chunk_empty; crypter_t *crypter = NULL; int enc_alg = OID_UNKNOWN; int content_enc_alg = OID_UNKNOWN; int version; int objectID; bool success = FALSE; contentInfo_t cInfo = empty_contentInfo; *data = chunk_empty; if (!pkcs7_parse_contentInfo(blob, 0, &cInfo)) { goto failed; } if (cInfo.type != OID_PKCS7_ENVELOPED_DATA) { DBG1(DBG_LIB, "pkcs7 content type is not envelopedData"); goto failed; } parser = asn1_parser_create(envelopedDataObjects, cInfo.content); parser->set_top_level(parser, 2); while (parser->iterate(parser, &objectID, &object)) { u_int level = parser->get_level(parser); switch (objectID) { case PKCS7_ENVELOPED_VERSION: version = object.len ? (int)*object.ptr : 0; DBG2(DBG_LIB, " v%d", version); if (version != 0) { DBG1(DBG_LIB, "envelopedData version is not 0"); goto end; } break; case PKCS7_RECIPIENT_INFO_VERSION: version = object.len ? (int)*object.ptr : 0; DBG2(DBG_LIB, " v%d", version); if (version != 0) { DBG1(DBG_LIB, "recipient info version is not 0"); goto end; } break; case PKCS7_ISSUER: { identification_t *issuer = identification_create_from_encoding( ID_DER_ASN1_DN, object); DBG2(DBG_LIB, " \"%Y\"", issuer); issuer->destroy(issuer); break; } case PKCS7_SERIAL_NUMBER: if (!chunk_equals(serialNumber, object)) { DBG1(DBG_LIB, "serial numbers do not match"); goto end; } break; case PKCS7_ENCRYPTION_ALG: enc_alg = asn1_parse_algorithmIdentifier(object, level, NULL); if (enc_alg != OID_RSA_ENCRYPTION) { DBG1(DBG_LIB, "only rsa encryption supported"); goto end; } break; case PKCS7_ENCRYPTED_KEY: if (!key->decrypt(key, ENCRYPT_RSA_PKCS1, object, &symmetric_key)) { DBG1(DBG_LIB, "symmetric key could not be decrypted with rsa"); goto end; } DBG4(DBG_LIB, "symmetric key %B", &symmetric_key); break; case PKCS7_CONTENT_TYPE: if (asn1_known_oid(object) != OID_PKCS7_DATA) { DBG1(DBG_LIB, "encrypted content not of type pkcs7 data"); goto end; } break; case PKCS7_CONTENT_ENC_ALGORITHM: content_enc_alg = asn1_parse_algorithmIdentifier(object, level, &iv); if (content_enc_alg == OID_UNKNOWN) { DBG1(DBG_LIB, "unknown content encryption algorithm"); goto end; } if (!asn1_parse_simple_object(&iv, ASN1_OCTET_STRING, level+1, "IV")) { DBG1(DBG_LIB, "IV could not be parsed"); goto end; } break; case PKCS7_ENCRYPTED_CONTENT: encrypted_content = object; break; } } success = parser->success(parser); end: parser->destroy(parser); if (!success) { goto failed; } success = FALSE; /* decrypt the content */ { encryption_algorithm_t alg; size_t key_size; crypter_t *crypter; alg = encryption_algorithm_from_oid(content_enc_alg, &key_size); if (alg == ENCR_UNDEFINED) { DBG1(DBG_LIB, "unsupported content encryption algorithm"); goto failed; } crypter = lib->crypto->create_crypter(lib->crypto, alg, key_size); if (crypter == NULL) { DBG1(DBG_LIB, "crypter %N not available", encryption_algorithm_names, alg); goto failed; } if (symmetric_key.len != crypter->get_key_size(crypter)) { DBG1(DBG_LIB, "symmetric key length %d is wrong", symmetric_key.len); goto failed; } if (iv.len != crypter->get_iv_size(crypter)) { DBG1(DBG_LIB, "IV length %d is wrong", iv.len); goto failed; } crypter->set_key(crypter, symmetric_key); crypter->decrypt(crypter, encrypted_content, iv, data); DBG4(DBG_LIB, "decrypted content with padding: %B", data); } /* remove the padding */ { u_char *pos = data->ptr + data->len - 1; u_char pattern = *pos; size_t padding = pattern; if (padding > data->len) { DBG1(DBG_LIB, "padding greater than data length"); goto failed; } data->len -= padding; while (padding-- > 0) { if (*pos-- != pattern) { DBG1(DBG_LIB, "wrong padding pattern"); goto failed; } } } success = TRUE; failed: DESTROY_IF(crypter); chunk_clear(&symmetric_key); if (!success) { free(data->ptr); } return success; }
/** * Parse a PKCS#7 signedData object */ bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, linked_list_t *certs, chunk_t *attributes, certificate_t *cacert) { asn1_parser_t *parser; chunk_t object; int digest_alg = OID_UNKNOWN; int enc_alg = OID_UNKNOWN; int signerInfos = 0; int version; int objectID; bool success = FALSE; contentInfo_t cInfo = empty_contentInfo; chunk_t encrypted_digest = chunk_empty; if (!pkcs7_parse_contentInfo(blob, 0, &cInfo)) { return FALSE; } if (cInfo.type != OID_PKCS7_SIGNED_DATA) { DBG1(DBG_LIB, "pkcs7 content type is not signedData"); return FALSE; } parser = asn1_parser_create(signedDataObjects, cInfo.content); parser->set_top_level(parser, 2); while (parser->iterate(parser, &objectID, &object)) { u_int level = parser->get_level(parser); switch (objectID) { case PKCS7_SIGNED_VERSION: version = object.len ? (int)*object.ptr : 0; DBG2(DBG_LIB, " v%d", version); break; case PKCS7_DIGEST_ALG: digest_alg = asn1_parse_algorithmIdentifier(object, level, NULL); break; case PKCS7_SIGNED_CONTENT_INFO: if (data != NULL) { pkcs7_parse_contentInfo(object, level, data); } break; case PKCS7_SIGNED_CERT: { certificate_t *cert; DBG2(DBG_LIB, " parsing pkcs7-wrapped certificate"); cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, BUILD_BLOB_ASN1_DER, object, BUILD_END); if (cert) { certs->insert_last(certs, cert); } } break; case PKCS7_SIGNER_INFO: signerInfos++; DBG2(DBG_LIB, " signer #%d", signerInfos); break; case PKCS7_SIGNER_INFO_VERSION: version = object.len ? (int)*object.ptr : 0; DBG2(DBG_LIB, " v%d", version); break; case PKCS7_SIGNED_ISSUER: { identification_t *issuer = identification_create_from_encoding( ID_DER_ASN1_DN, object); DBG2(DBG_LIB, " \"%Y\"", issuer); issuer->destroy(issuer); break; } case PKCS7_AUTH_ATTRIBUTES: if (attributes != NULL) { *attributes = object; *attributes->ptr = ASN1_SET; } break; case PKCS7_DIGEST_ALGORITHM: digest_alg = asn1_parse_algorithmIdentifier(object, level, NULL); break; case PKCS7_DIGEST_ENC_ALGORITHM: enc_alg = asn1_parse_algorithmIdentifier(object, level, NULL); break; case PKCS7_ENCRYPTED_DIGEST: encrypted_digest = object; } } success = parser->success(parser); parser->destroy(parser); if (!success) { return FALSE; } /* check the signature only if a cacert is available */ if (cacert != NULL) { public_key_t *key; signature_scheme_t scheme; scheme = signature_scheme_from_oid(digest_alg); if (scheme == SIGN_UNKNOWN) { DBG1(DBG_LIB, "unsupported signature scheme"); return FALSE; } if (signerInfos == 0) { DBG1(DBG_LIB, "no signerInfo object found"); return FALSE; } else if (signerInfos > 1) { DBG1(DBG_LIB, "more than one signerInfo object found"); return FALSE; } if (attributes->ptr == NULL) { DBG1(DBG_LIB, "no authenticatedAttributes object found"); return FALSE; } if (enc_alg != OID_RSA_ENCRYPTION) { DBG1(DBG_LIB, "only RSA digest encryption supported"); return FALSE; } /* verify the signature */ key = cacert->get_public_key(cacert); if (key == NULL) { DBG1(DBG_LIB, "no public key found in CA certificate"); return FALSE; } if (key->verify(key, scheme, *attributes, encrypted_digest)) { DBG2(DBG_LIB, "signature is valid"); } else { DBG1(DBG_LIB, "invalid signature"); success = FALSE; } key->destroy(key); } return success; }