/** * Free the dynamic memory used to store fetch requests */ static void free_fetch_request(fetch_req_t *req) { req->distributionPoints->destroy_function(req->distributionPoints, free); DESTROY_IF(req->issuer); free(req->authKeyID.ptr); free(req); }
/** * Create or replace a pool by name */ static u_int create_pool(char *name, chunk_t start, chunk_t end, int timeout) { enumerator_t *e; int pool; e = db->query(db, "SELECT id FROM pools WHERE name = ?", DB_TEXT, name, DB_UINT); if (e && e->enumerate(e, &pool)) { if (replace_pool == FALSE) { fprintf(stderr, "pool '%s' exists.\n", name); e->destroy(e); exit(EXIT_FAILURE); } del(name); } DESTROY_IF(e); if (db->execute(db, &pool, "INSERT INTO pools (name, start, end, timeout) VALUES (?, ?, ?, ?)", DB_TEXT, name, DB_BLOB, start, DB_BLOB, end, DB_INT, timeout*3600) != 1) { fprintf(stderr, "creating pool failed.\n"); exit(EXIT_FAILURE); } return pool; }
/** * Free myid module */ void free_myid(void) { enum myid_state s; for (s = MYID_UNKNOWN; s <= MYID_SPECIFIED; s++) { DESTROY_IF(myids[s]); } }
/* * Described in header */ bool botan_get_fingerprint(botan_pubkey_t pubkey, void *cache, cred_encoding_type_t type, chunk_t *fp) { hasher_t *hasher; chunk_t key; if (cache && lib->encoding->get_cache(lib->encoding, type, cache, fp)) { return TRUE; } switch (type) { case KEYID_PUBKEY_SHA1: /* subjectPublicKey -> use botan_pubkey_fingerprint() */ *fp = chunk_alloc(HASH_SIZE_SHA1); if (botan_pubkey_fingerprint(pubkey, "SHA-1", fp->ptr, &fp->len)) { chunk_free(fp); return FALSE; } break; case KEYID_PUBKEY_INFO_SHA1: /* subjectPublicKeyInfo -> use botan_pubkey_export(), then hash */ if (!botan_get_encoding(pubkey, PUBKEY_SPKI_ASN1_DER, &key)) { return FALSE; } hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); if (!hasher || !hasher->allocate_hash(hasher, key, fp)) { DBG1(DBG_LIB, "SHA1 hash algorithm not supported, " "fingerprinting failed"); DESTROY_IF(hasher); chunk_free(&key); return FALSE; } hasher->destroy(hasher); chunk_free(&key); break; default: return FALSE; } if (cache) { lib->encoding->cache(lib->encoding, type, cache, *fp); } return TRUE; }
/** * see section 3.8.9 of TCG TNC IF-IMV Specification 1.3 */ TNC_Result TNC_IMV_Terminate(TNC_IMVID imv_id) { if (!imv_attestation) { DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); return TNC_RESULT_NOT_INITIALIZED; } if (pts_creds) { pts_credmgr->remove_set(pts_credmgr, pts_creds->get_set(pts_creds)); pts_creds->destroy(pts_creds); } DESTROY_IF(pts_db); DESTROY_IF(pts_credmgr); libpts_deinit(); imv_attestation->destroy(imv_attestation); imv_attestation = NULL; return TNC_RESULT_SUCCESS; }
/** * Described in header. */ void libimcv_deinit(void) { if (ref_put(&libimcv_ref)) { imcv_pts_components->remove_vendor(imcv_pts_components, PEN_TCG); imcv_pts_components->remove_vendor(imcv_pts_components, PEN_ITA); imcv_pts_components->destroy(imcv_pts_components); imcv_pa_tnc_attributes->remove_vendor(imcv_pa_tnc_attributes, PEN_IETF); imcv_pa_tnc_attributes->remove_vendor(imcv_pa_tnc_attributes, PEN_ITA); imcv_pa_tnc_attributes->remove_vendor(imcv_pa_tnc_attributes, PEN_TCG); DESTROY_IF(imcv_pa_tnc_attributes); imcv_pa_tnc_attributes = NULL; DESTROY_IF(imcv_db); DESTROY_IF(imcv_sessions); DBG1(DBG_LIB, "libimcv terminated"); } if (ref_put(&libstrongswan_ref)) { library_deinit(); } }
/** * atexit() cleanup handler */ static void cleanup() { file_logger_t *logger; hook_t *hook; DESTROY_IF(conftest->test); lib->credmgr->remove_set(lib->credmgr, &conftest->creds->set); conftest->creds->destroy(conftest->creds); DESTROY_IF(conftest->actions); while (conftest->hooks->remove_last(conftest->hooks, (void**)&hook) == SUCCESS) { charon->bus->remove_listener(charon->bus, &hook->listener); hook->destroy(hook); } conftest->hooks->destroy(conftest->hooks); if (conftest->config) { if (charon->backends) { charon->backends->remove_backend(charon->backends, &conftest->config->backend); } conftest->config->destroy(conftest->config); } while (conftest->loggers->remove_last(conftest->loggers, (void**)&logger) == SUCCESS) { charon->bus->remove_logger(charon->bus, &logger->logger); logger->destroy(logger); } conftest->loggers->destroy(conftest->loggers); free(conftest->suite_dir); free(conftest); libcharon_deinit(); libhydra_deinit(); library_deinit(); }
/** * see section 3.8.9 of TCG TNC IF-IMV Specification 1.3 */ TNC_Result TNC_IMV_Terminate(TNC_IMVID imv_id) { if (!imv_os) { DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); return TNC_RESULT_NOT_INITIALIZED; } DESTROY_IF(os_db); imv_os->destroy(imv_os); imv_os = NULL; return TNC_RESULT_SUCCESS; }
/** * Described in header. */ void libimcv_deinit(void) { if (ref_put(&libimcv_ref)) { imcv_pa_tnc_attributes->remove_vendor(imcv_pa_tnc_attributes, PEN_IETF); imcv_pa_tnc_attributes->remove_vendor(imcv_pa_tnc_attributes, PEN_ITA); DESTROY_IF(imcv_pa_tnc_attributes); DBG1(DBG_LIB, "libimcv terminated"); } if (ref_put(&libstrongswan_ref)) { library_deinit(); } }
/** * 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); if (!hasher || !hasher->get_hash(hasher, pkcs10, digest.ptr)) { DESTROY_IF(hasher); return chunk_empty; } hasher->destroy(hasher); return chunk_to_hex(digest, NULL, FALSE); }
/** * 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); }
/** * Adds a senderNonce attribute to the given pkcs9 attribute list */ static bool add_senderNonce_attribute(pkcs9_t *pkcs9) { const size_t nonce_len = 16; u_char nonce_buf[nonce_len]; chunk_t senderNonce = { nonce_buf, nonce_len }; rng_t *rng; rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); if (!rng || !rng->get_bytes(rng, nonce_len, nonce_buf)) { DESTROY_IF(rng); return FALSE; } rng->destroy(rng); pkcs9->set_attribute(pkcs9, OID_PKI_SENDER_NONCE, senderNonce); return TRUE; }
/** * @brief exit scepclient * * @param status 0 = OK, 1 = general discomfort */ static void exit_scepclient(err_t message, ...) { int status = 0; if (creds) { lib->credmgr->remove_set(lib->credmgr, &creds->set); creds->destroy(creds); } DESTROY_IF(subject); DESTROY_IF(private_key); DESTROY_IF(public_key); DESTROY_IF(x509_signer); DESTROY_IF(x509_ca_enc); DESTROY_IF(x509_ca_sig); DESTROY_IF(pkcs10_req); subjectAltNames->destroy_offset(subjectAltNames, offsetof(identification_t, destroy)); free(pkcs1.ptr); free(pkcs7.ptr); free(serialNumber.ptr); free(transID.ptr); free(fingerprint.ptr); free(encoding.ptr); free(pkcs10_encoding.ptr); free(issuerAndSubject.ptr); free(getCertInitial.ptr); free(scep_response.ptr); options->destroy(options); /* print any error message to stderr */ if (message != NULL && *message != '\0') { va_list args; char m[8192]; va_start(args, message); vsnprintf(m, sizeof(m), message, args); va_end(args); fprintf(stderr, "error: %s\n", m); status = -1; } library_deinit(); exit(status); }
err_t scep_parse_response(chunk_t response, chunk_t transID, pkcs7_t **data, scep_attributes_t *attrs, certificate_t *signer_cert) { pkcs7_t *pkcs7; pkcs7 = pkcs7_create_from_chunk(response, 0); if (!pkcs7 || !pkcs7->parse_signedData(pkcs7, signer_cert)) { DESTROY_IF(pkcs7); return "error parsing the scep response"; } extract_attributes(pkcs7, attrs); if (!chunk_equals(transID, attrs->transID)) { pkcs7->destroy(pkcs7); return "transaction ID of scep response does not match"; } *data = pkcs7; return NULL; }
/** * 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); }
/** * Lookup/insert an identity */ u_int get_identity(identification_t *id) { enumerator_t *e; u_int row; /* look for peer identity in the identities table */ e = db->query(db, "SELECT id FROM identities WHERE type = ? AND data = ?", DB_INT, id->get_type(id), DB_BLOB, id->get_encoding(id), DB_UINT); if (e && e->enumerate(e, &row)) { e->destroy(e); return row; } DESTROY_IF(e); /* not found, insert new one */ if (db->execute(db, &row, "INSERT INTO identities (type,data) VALUES (?,?)", DB_INT, id->get_type(id), DB_BLOB, id->get_encoding(id)) != 1) { fprintf(stderr, "creating id '%Y' failed.\n", id); return 0; } return row; }
/** * Lookup/insert an attribute pool by name */ static u_int get_attr_pool(char *name) { enumerator_t *e; u_int row = 0; /* look for an existing attribute pool in the table */ e = db->query(db, "SELECT id FROM attribute_pools WHERE name = ?", DB_TEXT, name, DB_UINT); if (e && e->enumerate(e, &row)) { e->destroy(e); return row; } DESTROY_IF(e); /* not found, insert new one */ if (db->execute(db, &row, "INSERT INTO attribute_pools (name) VALUES (?)", DB_TEXT, name) != 1) { fprintf(stderr, "creating attribute pool '%s' failed.\n", name); return 0; } return row; }
/** * Load an encrypted private key from an ASN.1 encoded blob * Schemes per PKCS#5 (RFC 2898) */ static private_key_t *parse_encrypted_private_key(chunk_t blob) { asn1_parser_t *parser; chunk_t object; int objectID; private_key_t *key = NULL; pkcs5_t *pkcs5 = NULL; parser = asn1_parser_create(encryptedPKIObjects, blob); while (parser->iterate(parser, &objectID, &object)) { switch (objectID) { case EPKINFO_ENCRYPTION_ALGORITHM: { pkcs5 = pkcs5_from_algorithmIdentifier(object, parser->get_level(parser) + 1); if (!pkcs5) { goto end; } break; } case EPKINFO_ENCRYPTED_DATA: { key = decrypt_private_key(pkcs5, object); break; } } } end: DESTROY_IF(pkcs5); parser->destroy(parser); return key; }
/** * atexit handler to close db on shutdown */ static void cleanup(void) { db->destroy(db); DESTROY_IF(start); DESTROY_IF(end); }
int main(int argc, char *argv[]) { char *address = NULL; bool listen = FALSE; int port = 0, times = -1, res; identification_t *server, *client; tls_cache_t *cache; host_t *host; init(); while (TRUE) { struct option long_opts[] = { {"help", no_argument, NULL, 'h' }, {"connect", required_argument, NULL, 'c' }, {"listen", required_argument, NULL, 'l' }, {"port", required_argument, NULL, 'p' }, {"cert", required_argument, NULL, 'x' }, {"key", required_argument, NULL, 'k' }, {"times", required_argument, NULL, 't' }, {"debug", required_argument, NULL, 'd' }, {0,0,0,0 } }; switch (getopt_long(argc, argv, "", long_opts, NULL)) { case EOF: break; case 'h': usage(stdout, argv[0]); return 0; case 'x': if (!load_certificate(optarg)) { return 1; } continue; case 'k': if (!load_key(optarg)) { return 1; } continue; case 'l': listen = TRUE; /* fall */ case 'c': if (address) { usage(stderr, argv[0]); return 1; } address = optarg; continue; case 'p': port = atoi(optarg); continue; case 't': times = atoi(optarg); continue; case 'd': tls_level = atoi(optarg); continue; default: usage(stderr, argv[0]); return 1; } break; } if (!port || !address) { usage(stderr, argv[0]); return 1; } host = host_create_from_dns(address, 0, port); if (!host) { DBG1(DBG_TLS, "resolving hostname %s failed", address); return 1; } server = identification_create_from_string(address); cache = tls_cache_create(100, 30); if (listen) { res = serve(host, server, times, cache); } else { client = find_client_id(); res = run_client(host, server, client, times, cache); DESTROY_IF(client); } cache->destroy(cache); host->destroy(host); server->destroy(server); return res; }
/** * @brief openac main program * * @param argc number of arguments * @param argv pointer to the argument values */ int main(int argc, char **argv) { certificate_t *attr_cert = NULL; certificate_t *userCert = NULL; certificate_t *signerCert = NULL; private_key_t *signerKey = NULL; time_t notBefore = UNDEFINED_TIME; time_t notAfter = UNDEFINED_TIME; time_t validity = 0; char *keyfile = NULL; char *certfile = NULL; char *usercertfile = NULL; char *outfile = NULL; char *groups = ""; char buf[BUF_LEN]; chunk_t passphrase = { buf, 0 }; chunk_t serial = chunk_empty; chunk_t attr_chunk = chunk_empty; int status = 1; /* enable openac debugging hook */ dbg = openac_dbg; passphrase.ptr[0] = '\0'; openlog("openac", 0, LOG_AUTHPRIV); /* initialize library */ atexit(library_deinit); if (!library_init(NULL)) { exit(SS_RC_LIBSTRONGSWAN_INTEGRITY); } if (lib->integrity && !lib->integrity->check_file(lib->integrity, "openac", argv[0])) { fprintf(stderr, "integrity check of openac failed\n"); exit(SS_RC_DAEMON_INTEGRITY); } if (!lib->plugins->load(lib->plugins, lib->settings->get_str(lib->settings, "openac.load", PLUGINS))) { exit(SS_RC_INITIALIZATION_FAILED); } /* initialize optionsfrom */ options_t *options = options_create(); /* handle arguments */ for (;;) { static const struct option long_opts[] = { /* name, has_arg, flag, val */ { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'v' }, { "optionsfrom", required_argument, NULL, '+' }, { "quiet", no_argument, NULL, 'q' }, { "cert", required_argument, NULL, 'c' }, { "key", required_argument, NULL, 'k' }, { "password", required_argument, NULL, 'p' }, { "usercert", required_argument, NULL, 'u' }, { "groups", required_argument, NULL, 'g' }, { "days", required_argument, NULL, 'D' }, { "hours", required_argument, NULL, 'H' }, { "startdate", required_argument, NULL, 'S' }, { "enddate", required_argument, NULL, 'E' }, { "out", required_argument, NULL, 'o' }, { "debug", required_argument, NULL, 'd' }, { 0,0,0,0 } }; int c = getopt_long(argc, argv, "hv+:qc:k:p;u:g:D:H:S:E:o:d:", long_opts, NULL); /* Note: "breaking" from case terminates loop */ switch (c) { case EOF: /* end of flags */ break; case 0: /* long option already handled */ continue; case ':': /* diagnostic already printed by getopt_long */ case '?': /* diagnostic already printed by getopt_long */ case 'h': /* --help */ usage(NULL); status = 1; goto end; case 'v': /* --version */ printf("openac (strongSwan %s)\n", VERSION); status = 0; goto end; case '+': /* --optionsfrom <filename> */ { char path[BUF_LEN]; if (*optarg == '/') /* absolute pathname */ { strncpy(path, optarg, BUF_LEN); path[BUF_LEN-1] = '\0'; } else /* relative pathname */ { snprintf(path, BUF_LEN, "%s/%s", OPENAC_PATH, optarg); } if (!options->from(options, path, &argc, &argv, optind)) { status = 1; goto end; } } continue; case 'q': /* --quiet */ stderr_quiet = TRUE; continue; case 'c': /* --cert */ certfile = optarg; continue; case 'k': /* --key */ keyfile = optarg; continue; case 'p': /* --key */ if (strlen(optarg) >= BUF_LEN) { usage("passphrase too long"); goto end; } strncpy(passphrase.ptr, optarg, BUF_LEN); passphrase.len = min(strlen(optarg), BUF_LEN); continue; case 'u': /* --usercert */ usercertfile = optarg; continue; case 'g': /* --groups */ groups = optarg; continue; case 'D': /* --days */ if (optarg == NULL || !isdigit(optarg[0])) { usage("missing number of days"); goto end; } else { char *endptr; long days = strtol(optarg, &endptr, 0); if (*endptr != '\0' || endptr == optarg || days <= 0) { usage("<days> must be a positive number"); goto end; } validity += 24*3600*days; } continue; case 'H': /* --hours */ if (optarg == NULL || !isdigit(optarg[0])) { usage("missing number of hours"); goto end; } else { char *endptr; long hours = strtol(optarg, &endptr, 0); if (*endptr != '\0' || endptr == optarg || hours <= 0) { usage("<hours> must be a positive number"); goto end; } validity += 3600*hours; } continue; case 'S': /* --startdate */ if (optarg == NULL || strlen(optarg) != 15 || optarg[14] != 'Z') { usage("date format must be YYYYMMDDHHMMSSZ"); goto end; } else { chunk_t date = { optarg, 15 }; notBefore = asn1_to_time(&date, ASN1_GENERALIZEDTIME); } continue; case 'E': /* --enddate */ if (optarg == NULL || strlen(optarg) != 15 || optarg[14] != 'Z') { usage("date format must be YYYYMMDDHHMMSSZ"); goto end; } else { chunk_t date = { optarg, 15 }; notAfter = asn1_to_time(&date, ASN1_GENERALIZEDTIME); } continue; case 'o': /* --out */ outfile = optarg; continue; case 'd': /* --debug */ debug_level = atoi(optarg); continue; default: usage(""); status = 0; goto end; } /* break from loop */ break; } if (optind != argc) { usage("unexpected argument"); goto end; } DBG1(DBG_LIB, "starting openac (strongSwan Version %s)", VERSION); /* load the signer's RSA private key */ if (keyfile != NULL) { mem_cred_t *mem; shared_key_t *shared; mem = mem_cred_create(); lib->credmgr->add_set(lib->credmgr, &mem->set); shared = shared_key_create(SHARED_PRIVATE_KEY_PASS, chunk_clone(passphrase)); mem->add_shared(mem, shared, NULL); signerKey = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA, BUILD_FROM_FILE, keyfile, BUILD_END); lib->credmgr->remove_set(lib->credmgr, &mem->set); mem->destroy(mem); if (signerKey == NULL) { goto end; } DBG1(DBG_LIB, " loaded private key file '%s'", keyfile); } /* load the signer's X.509 certificate */ if (certfile != NULL) { signerCert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, BUILD_FROM_FILE, certfile, BUILD_END); if (signerCert == NULL) { goto end; } } /* load the users's X.509 certificate */ if (usercertfile != NULL) { userCert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, BUILD_FROM_FILE, usercertfile, BUILD_END); if (userCert == NULL) { goto end; } } /* compute validity interval */ validity = (validity)? validity : DEFAULT_VALIDITY; notBefore = (notBefore == UNDEFINED_TIME) ? time(NULL) : notBefore; notAfter = (notAfter == UNDEFINED_TIME) ? time(NULL) + validity : notAfter; /* build and parse attribute certificate */ if (userCert != NULL && signerCert != NULL && signerKey != NULL && outfile != NULL) { /* read the serial number and increment it by one */ serial = read_serial(); attr_cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_AC, BUILD_CERT, userCert, BUILD_NOT_BEFORE_TIME, notBefore, BUILD_NOT_AFTER_TIME, notAfter, BUILD_SERIAL, serial, BUILD_IETF_GROUP_ATTR, groups, BUILD_SIGNING_CERT, signerCert, BUILD_SIGNING_KEY, signerKey, BUILD_END); if (!attr_cert) { goto end; } /* write the attribute certificate to file */ if (attr_cert->get_encoding(attr_cert, CERT_ASN1_DER, &attr_chunk)) { if (chunk_write(attr_chunk, outfile, 0022, TRUE)) { DBG1(DBG_APP, " written attribute cert file '%s' (%d bytes)", outfile, attr_chunk.len); write_serial(serial); status = 0; } else { DBG1(DBG_APP, " writing attribute cert file '%s' failed: %s", outfile, strerror(errno)); } } } else { usage("some of the mandatory parameters --usercert --cert --key --out " "are missing"); } end: /* delete all dynamically allocated objects */ DESTROY_IF(signerKey); DESTROY_IF(signerCert); DESTROY_IF(userCert); DESTROY_IF(attr_cert); free(attr_chunk.ptr); free(serial.ptr); closelog(); dbg = dbg_default; options->destroy(options); exit(status); }
/** * Clean up credentials atexit() */ static void cleanup_creds() { DESTROY_IF(creds); }
/** * ipsec pool --status - show pool overview */ static void status(void) { enumerator_t *ns, *pool, *lease; host_t *server; chunk_t value; bool found = FALSE; /* enumerate IPv4 DNS servers */ ns = db->query(db, "SELECT value FROM attributes WHERE type = ?", DB_INT, INTERNAL_IP4_DNS, DB_BLOB); if (ns) { while (ns->enumerate(ns, &value)) { if (!found) { printf("dns servers:"); found = TRUE; } server = host_create_from_chunk(AF_INET, value, 0); if (server) { printf(" %H", server); server->destroy(server); } } ns->destroy(ns); } /* enumerate IPv6 DNS servers */ ns = db->query(db, "SELECT value FROM attributes WHERE type = ?", DB_INT, INTERNAL_IP6_DNS, DB_BLOB); if (ns) { while (ns->enumerate(ns, &value)) { if (!found) { printf("dns servers:"); found = TRUE; } server = host_create_from_chunk(AF_INET6, value, 0); if (server) { printf(" %H", server); server->destroy(server); } } ns->destroy(ns); } if (found) { printf("\n"); } else { printf("no dns servers found.\n"); } found = FALSE; /* enumerate IPv4 NBNS servers */ ns = db->query(db, "SELECT value FROM attributes WHERE type = ?", DB_INT, INTERNAL_IP4_NBNS, DB_BLOB); if (ns) { while (ns->enumerate(ns, &value)) { if (!found) { printf("nbns servers:"); found = TRUE; } server = host_create_from_chunk(AF_INET, value, 0); if (server) { printf(" %H", server); server->destroy(server); } } ns->destroy(ns); } /* enumerate IPv6 NBNS servers */ ns = db->query(db, "SELECT value FROM attributes WHERE type = ?", DB_INT, INTERNAL_IP6_NBNS, DB_BLOB); if (ns) { while (ns->enumerate(ns, &value)) { if (!found) { printf("nbns servers:"); found = TRUE; } server = host_create_from_chunk(AF_INET6, value, 0); if (server) { printf(" %H", server); server->destroy(server); } } ns->destroy(ns); } if (found) { printf("\n"); } else { printf("no nbns servers found.\n"); } found = FALSE; pool = db->query(db, "SELECT id, name, start, end, timeout FROM pools", DB_INT, DB_TEXT, DB_BLOB, DB_BLOB, DB_UINT); if (pool) { char *name; chunk_t start_chunk, end_chunk; host_t *start, *end; u_int id, timeout, online = 0, used = 0, size = 0; while (pool->enumerate(pool, &id, &name, &start_chunk, &end_chunk, &timeout)) { if (!found) { printf("%8s %15s %15s %8s %6s %11s %11s\n", "name", "start", "end", "timeout", "size", "online", "usage"); found = TRUE; } start = host_create_from_chunk(AF_UNSPEC, start_chunk, 0); end = host_create_from_chunk(AF_UNSPEC, end_chunk, 0); if (start->is_anyaddr(start) && end->is_anyaddr(end)) { printf("%8s %15s %15s ", name, "n/a", "n/a"); } else { printf("%8s %15H %15H ", name, start, end); } if (timeout) { printf("%7dh ", timeout/3600); } else { printf("%8s ", "static"); } /* get total number of hosts in the pool */ lease = db->query(db, "SELECT COUNT(*) FROM addresses " "WHERE pool = ?", DB_UINT, id, DB_INT); if (lease) { lease->enumerate(lease, &size); lease->destroy(lease); } if (!size) { /* empty pool */ printf("%6d %11s %11s ", 0, "n/a", "n/a"); goto next_pool; } printf("%6d ", size); /* get number of online hosts */ lease = db->query(db, "SELECT COUNT(*) FROM addresses " "WHERE pool = ? AND released = 0", DB_UINT, id, DB_INT); if (lease) { lease->enumerate(lease, &online); lease->destroy(lease); } printf("%5d (%2d%%) ", online, online*100/size); /* get number of online or valid leases */ lease = db->query(db, "SELECT COUNT(*) FROM addresses " "WHERE addresses.pool = ? " "AND ((? AND acquired != 0) " " OR released = 0 OR released > ?) ", DB_UINT, id, DB_UINT, !timeout, DB_UINT, time(NULL) - timeout, DB_UINT); if (lease) { lease->enumerate(lease, &used); lease->destroy(lease); } printf("%5d (%2d%%) ", used, used*100/size); next_pool: printf("\n"); DESTROY_IF(start); DESTROY_IF(end); } pool->destroy(pool); } if (!found) { printf("no pools found.\n"); } }
/** * Clean up connection definition atexit() */ static void cleanup_conn() { DESTROY_IF(conn); }
/** * ipsec pool --resize - resize a pool */ static void resize(char *name, host_t *end) { enumerator_t *query; chunk_t old_addr, new_addr, cur_addr; u_int id, count; host_t *old_end; new_addr = end->get_address(end); query = db->query(db, "SELECT id, end FROM pools WHERE name = ?", DB_TEXT, name, DB_UINT, DB_BLOB); if (!query || !query->enumerate(query, &id, &old_addr)) { DESTROY_IF(query); fprintf(stderr, "resizing pool failed.\n"); exit(EXIT_FAILURE); } if (old_addr.len != new_addr.len || memcmp(new_addr.ptr, old_addr.ptr, old_addr.len) < 0) { fprintf(stderr, "shrinking of pools not supported.\n"); query->destroy(query); exit(EXIT_FAILURE); } cur_addr = chunk_clonea(old_addr); count = get_pool_size(old_addr, new_addr) - 1; query->destroy(query); /* Check whether pool is resizable */ old_end = host_create_from_chunk(AF_UNSPEC, old_addr, 0); if (old_end && old_end->is_anyaddr(old_end)) { fprintf(stderr, "pool is not resizable.\n"); old_end->destroy(old_end); exit(EXIT_FAILURE); } DESTROY_IF(old_end); db->transaction(db, FALSE); if (db->execute(db, NULL, "UPDATE pools SET end = ? WHERE name = ?", DB_BLOB, new_addr, DB_TEXT, name) <= 0) { fprintf(stderr, "pool '%s' not found.\n", name); exit(EXIT_FAILURE); } printf("allocating %d new addresses... ", count); fflush(stdout); while (count-- > 0) { chunk_increment(cur_addr); db->execute(db, NULL, "INSERT INTO addresses (pool, address, identity, acquired, released) " "VALUES (?, ?, ?, ?, ?)", DB_UINT, id, DB_BLOB, cur_addr, DB_UINT, 0, DB_UINT, 0, DB_UINT, 1); } db->commit(db); printf("done.\n"); }
/** * 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); } }
/** * Determine the type of the attribute and its value */ static bool parse_attributes(char *name, char *value, value_type_t *value_type, configuration_attribute_type_t *type, configuration_attribute_type_t *type_ip6, chunk_t *blob) { host_t *addr = NULL, *mask = NULL; chunk_t addr_chunk, mask_chunk, blob_next; char *text = "", *pos_addr, *pos_mask, *pos_next, *endptr; int i; switch (*value_type) { case VALUE_STRING: *blob = chunk_create(value, strlen(value)); *blob = chunk_clone(*blob); break; case VALUE_HEX: *blob = chunk_from_hex(chunk_create(value, strlen(value)), NULL); break; case VALUE_ADDR: addr = host_create_from_string(value, 0); if (addr == NULL) { fprintf(stderr, "invalid IP address: '%s'.\n", value); return FALSE; } addr_chunk = addr->get_address(addr); *blob = chunk_clone(addr_chunk); break; case VALUE_SUBNET: *blob = chunk_empty; pos_next = value; do { pos_addr = pos_next; pos_next = strchr(pos_next, ','); if (pos_next) { *pos_next = '\0'; pos_next += 1; } pos_mask = strchr(pos_addr, '/'); if (pos_mask == NULL) { fprintf(stderr, "invalid IPv4 subnet: '%s'.\n", pos_addr); free(blob->ptr); return FALSE; } *pos_mask = '\0'; pos_mask += 1; addr = host_create_from_string(pos_addr, 0); mask = host_create_from_string(pos_mask, 0); if (addr == NULL || addr->get_family(addr) != AF_INET || mask == NULL || mask->get_family(addr) != AF_INET) { fprintf(stderr, "invalid IPv4 subnet: '%s/%s'.\n", pos_addr, pos_mask); DESTROY_IF(addr); DESTROY_IF(mask); free(blob->ptr); return FALSE; } addr_chunk = addr->get_address(addr); mask_chunk = mask->get_address(mask); blob_next = chunk_alloc(blob->len + UNITY_NETWORK_LEN); memcpy(blob_next.ptr, blob->ptr, blob->len); pos_addr = blob_next.ptr + blob->len; memset(pos_addr, 0x00, UNITY_NETWORK_LEN); memcpy(pos_addr, addr_chunk.ptr, 4); memcpy(pos_addr + 4, mask_chunk.ptr, 4); addr->destroy(addr); addr = NULL; mask->destroy(mask); chunk_free(blob); *blob = blob_next; } while (pos_next); break; case VALUE_NONE: *blob = chunk_empty; break; } /* init the attribute type */ *type = 0; *type_ip6 = 0; for (i = 0; i < countof(attr_info); i++) { if (strcaseeq(name, attr_info[i].keyword)) { *type = attr_info[i].type; *type_ip6 = attr_info[i].type_ip6; if (*value_type == VALUE_NONE) { *value_type = attr_info[i].value_type; return TRUE; } if (*value_type != attr_info[i].value_type && *value_type != VALUE_HEX) { switch (attr_info[i].value_type) { case VALUE_STRING: text = "a string"; break; case VALUE_HEX: text = "a hex"; break; case VALUE_ADDR: text = "an IP address"; break; case VALUE_SUBNET: text = "a subnet"; break; case VALUE_NONE: text = "no"; break; } fprintf(stderr, "the %s attribute requires %s value.\n", name, text); DESTROY_IF(addr); free(blob->ptr); return FALSE; } if (*value_type == VALUE_ADDR) { *type = (addr->get_family(addr) == AF_INET) ? attr_info[i].type : attr_info[i].type_ip6; addr->destroy(addr); } else if (*value_type == VALUE_HEX) { *value_type = attr_info[i].value_type; if (*value_type == VALUE_ADDR) { if (blob->len == 16) { *type = attr_info[i].type_ip6; } else if (blob->len != 4) { fprintf(stderr, "the %s attribute requires " "a valid IP address.\n", name); free(blob->ptr); return FALSE; } } } return TRUE; } } /* clean up */ DESTROY_IF(addr); /* is the attribute type numeric? */ *type = strtol(name, &endptr, 10); if (*endptr != '\0') { fprintf(stderr, "the %s attribute is not recognized.\n", name); free(blob->ptr); return FALSE; } if (*type < 1 || *type > 32767) { fprintf(stderr, "the attribute type must lie in the range 1..32767.\n"); free(blob->ptr); return FALSE; } if (*value_type == VALUE_NONE) { *value_type = VALUE_HEX; } return TRUE; }
static bool do_test_gcm(test_vector_t *test) { encryption_algorithm_t alg; chunk_t key, iv; aead_t *aead; size_t saltlen, ivlen; switch (ctx.icvlen / 8) { case 8: alg = ENCR_AES_GCM_ICV8; break; case 12: alg = ENCR_AES_GCM_ICV12; break; case 16: alg = ENCR_AES_GCM_ICV16; break; default: DBG1(DBG_APP, "unsupported ICV length: %d", ctx.icvlen); return FALSE; } aead = lib->crypto->create_aead(lib->crypto, alg, test->key.len, 4); if (!aead) { DBG1(DBG_APP, "algorithm %N or key length (%d bits) not supported", encryption_algorithm_names, alg, test->key.len * 8); return FALSE; } /* our API is quite RFC 4106 specific, that is, part of the IV is provided * at the end of the key. */ saltlen = aead->get_key_size(aead) - test->key.len; ivlen = aead->get_iv_size(aead); if (ctx.ivlen / 8 != saltlen + ivlen) { DBG1(DBG_APP, "unsupported IV length: %d", ctx.ivlen); aead->destroy(aead); return FALSE; } if (!test->external_iv) { rng_t *rng; /* the IV consists of saltlen random bytes (usually additional keymat) * followed by a counter, zero here */ test->iv = chunk_alloc(saltlen + ivlen); memset(test->iv.ptr, 0, test->iv.len); rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG); if (!rng || !rng->get_bytes(rng, saltlen, test->iv.ptr)) { DBG1(DBG_APP, "failed to generate IV"); DESTROY_IF(rng); aead->destroy(aead); return FALSE; } rng->destroy(rng); } key = chunk_alloca(test->key.len + saltlen); memcpy(key.ptr, test->key.ptr, test->key.len); memcpy(key.ptr + test->key.len, test->iv.ptr, saltlen); iv = chunk_alloca(ivlen); memcpy(iv.ptr, test->iv.ptr + saltlen, iv.len); if (!aead->set_key(aead, key)) { DBG1(DBG_APP, "failed to set key"); aead->destroy(aead); return FALSE; } if (ctx.decrypt) { /* the ICV is expected to follow the cipher text */ chunk_t cipher = chunk_cata("cc", test->cipher, test->icv); /* store if the verification of the ICV verification is successful */ test->success = aead->decrypt(aead, cipher, test->aad, iv, &test->plain); } else { if (!aead->encrypt(aead, test->plain, test->aad, iv, &test->cipher)) { DBG1(DBG_APP, "encryption failed"); aead->destroy(aead); return FALSE; } /* copy ICV from the end of the cipher text */ test->icv = chunk_alloc(ctx.icvlen / 8); test->cipher.len -= test->icv.len; memcpy(test->icv.ptr, test->cipher.ptr + test->cipher.len, test->icv.len); } aead->destroy(aead); return TRUE; }
/** * atexit() cleanup for dispatcher */ void dispatcher_cleanup() { DESTROY_IF(dispatcher); }
static void do_args(int argc, char *argv[]) { char *name = "", *value = "", *filter = ""; char *pool = NULL, *identity = NULL, *addresses = NULL; value_type_t value_type = VALUE_NONE; int timeout = 0; bool utc = FALSE, hexout = FALSE; enum { OP_UNDEF, OP_USAGE, OP_STATUS, OP_STATUS_ATTR, OP_ADD, OP_ADD_ATTR, OP_DEL, OP_DEL_ATTR, OP_SHOW_ATTR, OP_RESIZE, OP_LEASES, OP_PURGE, OP_BATCH } operation = OP_UNDEF; /* reinit getopt state */ optind = 0; while (TRUE) { int c; struct option long_opts[] = { { "help", no_argument, NULL, 'h' }, { "utc", no_argument, NULL, 'u' }, { "status", no_argument, NULL, 'w' }, { "add", required_argument, NULL, 'a' }, { "replace", required_argument, NULL, 'c' }, { "del", required_argument, NULL, 'd' }, { "resize", required_argument, NULL, 'r' }, { "leases", no_argument, NULL, 'l' }, { "purge", required_argument, NULL, 'p' }, { "statusattr", no_argument, NULL, '1' }, { "addattr", required_argument, NULL, '2' }, { "delattr", required_argument, NULL, '3' }, { "showattr", no_argument, NULL, '4' }, { "batch", required_argument, NULL, 'b' }, { "start", required_argument, NULL, 's' }, { "end", required_argument, NULL, 'e' }, { "addresses", required_argument, NULL, 'y' }, { "timeout", required_argument, NULL, 't' }, { "filter", required_argument, NULL, 'f' }, { "addr", required_argument, NULL, 'v' }, { "mask", required_argument, NULL, 'v' }, { "server", required_argument, NULL, 'v' }, { "subnet", required_argument, NULL, 'n' }, { "string", required_argument, NULL, 'g' }, { "hex", required_argument, NULL, 'x' }, { "hexout", no_argument, NULL, '5' }, { "pool", required_argument, NULL, '6' }, { "identity", required_argument, NULL, '7' }, { 0,0,0,0 } }; c = getopt_long(argc, argv, "", long_opts, NULL); switch (c) { case EOF: break; case 'h': operation = OP_USAGE; break; case 'w': operation = OP_STATUS; break; case '1': operation = OP_STATUS_ATTR; break; case 'u': utc = TRUE; continue; case 'c': replace_pool = TRUE; /* fallthrough */ case 'a': name = optarg; operation = is_attribute(name) ? OP_ADD_ATTR : OP_ADD; if (replace_pool && operation == OP_ADD_ATTR) { fprintf(stderr, "invalid pool name: " "reserved for '%s' attribute.\n", optarg); usage(); exit(EXIT_FAILURE); } continue; case '2': name = optarg; operation = OP_ADD_ATTR; continue; case 'd': name = optarg; operation = is_attribute(name) ? OP_DEL_ATTR : OP_DEL; continue; case '3': name = optarg; operation = OP_DEL_ATTR; continue; case '4': operation = OP_SHOW_ATTR; continue; case 'r': name = optarg; operation = OP_RESIZE; continue; case 'l': operation = OP_LEASES; continue; case 'p': name = optarg; operation = OP_PURGE; continue; case 'b': name = optarg; if (operation == OP_BATCH) { fprintf(stderr, "--batch commands can not be nested\n"); exit(EXIT_FAILURE); } operation = OP_BATCH; continue; case 's': DESTROY_IF(start); start = host_create_from_string(optarg, 0); if (start == NULL) { fprintf(stderr, "invalid start address: '%s'.\n", optarg); usage(); exit(EXIT_FAILURE); } continue; case 'e': DESTROY_IF(end); end = host_create_from_string(optarg, 0); if (end == NULL) { fprintf(stderr, "invalid end address: '%s'.\n", optarg); usage(); exit(EXIT_FAILURE); } continue; case 't': timeout = atoi(optarg); if (timeout == 0 && strcmp(optarg, "0") != 0) { fprintf(stderr, "invalid timeout '%s'.\n", optarg); usage(); exit(EXIT_FAILURE); } continue; case 'f': filter = optarg; continue; case 'y': addresses = optarg; continue; case 'g': value_type = VALUE_STRING; value = optarg; continue; case 'n': value_type = VALUE_SUBNET; value = optarg; continue; case 'v': value_type = VALUE_ADDR; value = optarg; continue; case 'x': value_type = VALUE_HEX; value = optarg; continue; case '5': hexout = TRUE; continue; case '6': pool = optarg; continue; case '7': identity = optarg; continue; default: usage(); exit(EXIT_FAILURE); break; } break; } switch (operation) { case OP_USAGE: usage(); break; case OP_STATUS: status(); break; case OP_STATUS_ATTR: status_attr(hexout); break; case OP_ADD: if (addresses != NULL) { add_addresses(name, addresses, timeout); } else if (start != NULL && end != NULL) { add(name, start, end, timeout); } else { fprintf(stderr, "missing arguments.\n"); usage(); exit(EXIT_FAILURE); } break; case OP_ADD_ATTR: if (value_type == VALUE_NONE) { fprintf(stderr, "missing arguments.\n"); usage(); exit(EXIT_FAILURE); } if (identity && !pool) { fprintf(stderr, "--identity option can't be used without --pool.\n"); usage(); exit(EXIT_FAILURE); } add_attr(name, pool, identity, value, value_type); break; case OP_DEL: del(name); break; case OP_DEL_ATTR: if (identity && !pool) { fprintf(stderr, "--identity option can't be used without --pool.\n"); usage(); exit(EXIT_FAILURE); } del_attr(name, pool, identity, value, value_type); break; case OP_SHOW_ATTR: show_attr(); break; case OP_RESIZE: if (end == NULL) { fprintf(stderr, "missing arguments.\n"); usage(); exit(EXIT_FAILURE); } resize(name, end); break; case OP_LEASES: leases(filter, utc); break; case OP_PURGE: purge(name); break; case OP_BATCH: if (name == NULL) { fprintf(stderr, "missing arguments.\n"); usage(); exit(EXIT_FAILURE); } batch(argv[0], name); break; default: usage(); exit(EXIT_FAILURE); } }