/* Reads a certificate file */ static int read_cert_file(gnutls_certificate_credentials_t res, gnutls_privkey_t key, const char *certfile, gnutls_x509_crt_fmt_t type) { int ret; size_t size; char *data; if (gnutls_url_is_supported(certfile)) { return read_cert_url(res, key, certfile); } data = read_binary_file(certfile, &size); if (data == NULL) { gnutls_assert(); return GNUTLS_E_FILE_ERROR; } ret = read_cert_mem(res, key, data, size, type); free(data); return ret; }
/* Load the CA's private key. */ gnutls_privkey_t load_ca_private_key(common_info_st * info) { gnutls_privkey_t key; gnutls_datum_t dat; size_t size; if (info->ca_privkey == NULL) { fprintf(stderr, "missing --load-ca-privkey\n"); exit(1); } if (gnutls_url_is_supported(info->ca_privkey) != 0) return _load_url_privkey(info->ca_privkey); dat.data = (void *) read_binary_file(info->ca_privkey, &size); dat.size = size; if (!dat.data) { fprintf(stderr, "reading --load-ca-privkey: %s\n", info->ca_privkey); exit(1); } key = _load_privkey(&dat, info); free(dat.data); return key; }
/* Load the CA's private key. */ gnutls_privkey_t load_ca_private_key (common_info_st * info) { gnutls_privkey_t key; gnutls_datum_t dat; size_t size; if (info->ca_privkey == NULL) error (EXIT_FAILURE, 0, "missing --load-ca-privkey"); if (gnutls_url_is_supported(info->ca_privkey) != 0) return _load_url_privkey(info->ca_privkey); dat.data = (void*)read_binary_file (info->ca_privkey, &size); dat.size = size; if (!dat.data) error (EXIT_FAILURE, errno, "reading --load-ca-privkey: %s", info->ca_privkey); key = _load_privkey(&dat, info); free (dat.data); 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) { 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; }
/* Reads PKCS-1 RSA private key file or a DSA file (in the format openssl * stores it). */ int _gnutls_read_key_file(gnutls_certificate_credentials_t res, const char *keyfile, gnutls_x509_crt_fmt_t type, const char *pass, unsigned int flags, gnutls_privkey_t *rkey) { int ret; size_t size; char *data; if (_gnutls_url_is_known(keyfile)) { if (gnutls_url_is_supported(keyfile)) { /* if no PIN function is specified, and we have a PIN, * specify one */ if (pass != NULL && res->pin.cb == NULL) { snprintf(res->pin_tmp, sizeof(res->pin_tmp), "%s", pass); gnutls_certificate_set_pin_function(res, tmp_pin_cb, res->pin_tmp); } return read_key_url(res, keyfile, rkey); } else return gnutls_assert_val (GNUTLS_E_UNIMPLEMENTED_FEATURE); } data = read_binary_file(keyfile, &size); if (data == NULL) { gnutls_assert(); return GNUTLS_E_FILE_ERROR; } ret = _gnutls_read_key_mem(res, data, size, type, pass, flags, rkey); free(data); return ret; }
void sec_mod_server(struct cfg_st* config, const char* socket_file) { struct sockaddr_un sa; socklen_t sa_len; int cfd, ret, e; unsigned i, buffer_size, type; gnutls_privkey_t *key; uint8_t *buffer; unsigned key_size = config->key_size; struct pin_st pins; gnutls_datum_t data, out; uint16_t length; struct iovec iov[2]; int sd; #if defined(SO_PEERCRED) && defined(HAVE_STRUCT_UCRED) struct ucred cr; socklen_t cr_len; #endif ocsignal(SIGHUP, SIG_IGN); ocsignal(SIGINT, SIG_DFL); ocsignal(SIGTERM, SIG_DFL); #ifdef HAVE_PKCS11 ret = gnutls_pkcs11_reinit(); if (ret < 0) { syslog(LOG_WARNING, "error in PKCS #11 reinitialization: %s", gnutls_strerror(ret)); } #endif buffer_size = 8*1024; buffer = malloc(buffer_size); if (buffer == NULL) { syslog(LOG_ERR, "error in memory allocation"); exit(1); } memset(&sa, 0, sizeof(sa)); sa.sun_family = AF_UNIX; snprintf(sa.sun_path, sizeof(sa.sun_path), "%s", socket_file); remove(socket_file); sd = socket(AF_UNIX, SOCK_STREAM, 0); if (sd == -1) { e = errno; syslog(LOG_ERR, "could not create socket '%s': %s", socket_file, strerror(e)); exit(1); } umask(066); ret = bind(sd, (struct sockaddr *)&sa, SUN_LEN(&sa)); if (ret == -1) { e = errno; syslog(LOG_ERR, "could not bind socket '%s': %s", socket_file, strerror(e)); exit(1); } ret = chown(socket_file, config->uid, config->gid); if (ret == -1) { e = errno; syslog(LOG_ERR, "could not chown socket '%s': %s", socket_file, strerror(e)); } ret = listen(sd, 1024); if (ret == -1) { e = errno; syslog(LOG_ERR, "could not listen to socket '%s': %s", socket_file, strerror(e)); exit(1); } ret = load_pins(config, &pins); if (ret < 0) { syslog(LOG_ERR, "error loading PIN files"); exit(1); } key = malloc(sizeof(*key)*config->key_size); if (key == NULL) { syslog(LOG_ERR, "error in memory allocation"); exit(1); } /* read private keys */ for (i=0;i<key_size;i++) { ret = gnutls_privkey_init(&key[i]); GNUTLS_FATAL_ERR(ret); /* load the private key */ if (gnutls_url_is_supported(config->key[i]) != 0) { gnutls_privkey_set_pin_function (key[i], pin_callback, &pins); ret = gnutls_privkey_import_url(key[i], config->key[i], 0); GNUTLS_FATAL_ERR(ret); } else { ret = gnutls_load_file(config->key[i], &data); if (ret < 0) { syslog(LOG_ERR, "error loading file '%s'", config->key[i]); GNUTLS_FATAL_ERR(ret); } ret = gnutls_privkey_import_x509_raw(key[i], &data, GNUTLS_X509_FMT_PEM, NULL, 0); GNUTLS_FATAL_ERR(ret); gnutls_free(data.data); } } syslog(LOG_INFO, "sec-mod initialized (socket: %s)", socket_file); for (;;) { sa_len = sizeof(sa); cfd = accept(sd, (struct sockaddr *)&sa, &sa_len); if (cfd == -1) { e = errno; syslog(LOG_ERR, "sec-mod error accepting connection: %s", strerror(e)); continue; } #if defined(SO_PEERCRED) && defined(HAVE_STRUCT_UCRED) cr_len = sizeof(cr); ret = getsockopt(cfd, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len); if (ret == -1) { e = errno; syslog(LOG_ERR, "sec-mod error obtaining peer credentials: %s", strerror(e)); goto cont; } syslog(LOG_DEBUG, "sec-mod received request from pid %u and uid %u", (unsigned)cr.pid, (unsigned)cr.uid); if (cr.uid != config->uid || cr.gid != config->gid) { syslog(LOG_ERR, "sec-mod received unauthorized request from pid %u and uid %u", (unsigned)cr.pid, (unsigned)cr.uid); goto cont; } #endif /* read request */ ret = recv(cfd, buffer, buffer_size, 0); if (ret == 0) goto cont; else if (ret <= 2) { e = errno; syslog(LOG_ERR, "error receiving sec-mod data: %s", strerror(e)); goto cont; } /* calculate */ i = buffer[0]; type = buffer[1]; if (i >= key_size) { syslog(LOG_ERR, "sec-mod received out-of-bounds key index"); goto cont; } data.data = &buffer[2]; data.size = ret - 2; if (type == 'S') { #if GNUTLS_VERSION_NUMBER >= 0x030200 ret = gnutls_privkey_sign_hash(key[i], 0, GNUTLS_PRIVKEY_SIGN_FLAG_TLS1_RSA, &data, &out); #else ret = gnutls_privkey_sign_raw_data(key[i], 0, &data, &out); #endif } else if (type == 'D') { ret = gnutls_privkey_decrypt_data(key[i], 0, &data, &out); } else { syslog(LOG_ERR, "unknown type 0x%.2x", type); goto cont; } if (ret < 0) { syslog(LOG_ERR, "sec-mod error in crypto operation: %s", gnutls_strerror(ret)); goto cont; } /* write reply */ length = out.size; iov[0].iov_base = &length; iov[0].iov_len = 2; iov[1].iov_base = out.data; iov[1].iov_len = out.size; ret = writev(cfd, iov, 2); if (ret == -1) { e = errno; syslog(LOG_ERR, "sec-mod error in writev: %s", strerror(e)); } gnutls_free(out.data); cont: close(cfd); } }
static int load_keys(sec_mod_st *sec, unsigned force) { unsigned i, need_reload = 0; int ret; struct pin_st pins; static time_t last_access = 0; for (i = 0; i < sec->perm_config->key_size; i++) { if (need_file_reload(sec->perm_config->key[i], last_access) != 0) { need_reload = 1; break; } } if (need_reload == 0) return 0; last_access = time(0); ret = load_pins(sec->perm_config, &pins); if (ret < 0) { seclog(sec, LOG_ERR, "error loading PIN files"); exit(1); } /* Reminder: the number of private keys or their filenames cannot be changed on reload */ if (sec->key == NULL) { sec->key_size = sec->perm_config->key_size; sec->key = talloc_zero_size(sec, sizeof(*sec->key) * sec->perm_config->key_size); if (sec->key == NULL) { seclog(sec, LOG_ERR, "error in memory allocation"); exit(1); } } /* read private keys */ for (i = 0; i < sec->key_size; i++) { gnutls_privkey_t p; ret = gnutls_privkey_init(&p); CHECK_LOOP_ERR(ret); /* load the private key */ if (gnutls_url_is_supported(sec->perm_config->key[i]) != 0) { gnutls_privkey_set_pin_function(p, pin_callback, &pins); ret = gnutls_privkey_import_url(p, sec->perm_config->key[i], 0); CHECK_LOOP_ERR(ret); } else { gnutls_datum_t data; ret = gnutls_load_file(sec->perm_config->key[i], &data); if (ret < 0) { seclog(sec, LOG_ERR, "error loading file '%s'", sec->perm_config->key[i]); CHECK_LOOP_ERR(ret); } ret = gnutls_privkey_import_x509_raw(p, &data, GNUTLS_X509_FMT_PEM, NULL, 0); if (ret == GNUTLS_E_DECRYPTION_FAILED && pins.pin[0]) { ret = gnutls_privkey_import_x509_raw(p, &data, GNUTLS_X509_FMT_PEM, pins.pin, 0); } CHECK_LOOP_ERR(ret); gnutls_free(data.data); } if (sec->key[i] != NULL) { gnutls_privkey_deinit(sec->key[i]); } sec->key[i] = p; } return 0; }
/* Load the certificate and the private key. */ static void load_keys (void) { unsigned int crt_num; int ret; unsigned int i; gnutls_datum_t data = { NULL, 0 }; gnutls_x509_crt_t crt_list[MAX_CRT]; unsigned char keyid[GNUTLS_OPENPGP_KEYID_SIZE]; if (x509_certfile != NULL && x509_keyfile != NULL) { #ifdef ENABLE_PKCS11 if (strncmp (x509_certfile, "pkcs11:", 7) == 0) { crt_num = 1; gnutls_x509_crt_init (&crt_list[0]); gnutls_x509_crt_set_pin_function(crt_list[0], pin_callback, NULL); ret = gnutls_x509_crt_import_pkcs11_url (crt_list[0], x509_certfile, 0); if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) ret = gnutls_x509_crt_import_pkcs11_url (crt_list[0], x509_certfile, GNUTLS_PKCS11_OBJ_FLAG_LOGIN); if (ret < 0) { fprintf (stderr, "*** Error loading cert file.\n"); exit (1); } x509_crt_size = 1; } else #endif /* ENABLE_PKCS11 */ { ret = gnutls_load_file (x509_certfile, &data); if (ret < 0) { fprintf (stderr, "*** Error loading cert file.\n"); exit (1); } crt_num = MAX_CRT; ret = gnutls_x509_crt_list_import (crt_list, &crt_num, &data, x509ctype, GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED); if (ret < 0) { if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) { fprintf (stderr, "*** Error loading cert file: Too many certs %d\n", crt_num); } else { fprintf (stderr, "*** Error loading cert file: %s\n", gnutls_strerror (ret)); } exit (1); } x509_crt_size = ret; } for (i=0;i<x509_crt_size;i++) { ret = gnutls_pcert_import_x509(&x509_crt[i], crt_list[i], 0); if (ret < 0) { fprintf(stderr, "*** Error importing crt to pcert: %s\n", gnutls_strerror(ret)); exit(1); } gnutls_x509_crt_deinit(crt_list[i]); } gnutls_free (data.data); ret = gnutls_privkey_init(&x509_key); if (ret < 0) { fprintf (stderr, "*** Error initializing key: %s\n", gnutls_strerror (ret)); exit (1); } gnutls_privkey_set_pin_function(x509_key, pin_callback, NULL); if (gnutls_url_is_supported(x509_keyfile) != 0) { ret = gnutls_privkey_import_url (x509_key, x509_keyfile, 0); if (ret < 0) { fprintf (stderr, "*** Error loading url: %s\n", gnutls_strerror (ret)); exit (1); } } else { ret = gnutls_load_file (x509_keyfile, &data); if (ret < 0) { fprintf (stderr, "*** Error loading key file.\n"); exit (1); } ret = gnutls_privkey_import_x509_raw( x509_key, &data, x509ctype, NULL, 0); if (ret < 0) { fprintf (stderr, "*** Error loading url: %s\n", gnutls_strerror (ret)); exit (1); } gnutls_free(data.data); } fprintf (stdout, "Processed %d client X.509 certificates...\n", x509_crt_size); } #ifdef ENABLE_OPENPGP if (HAVE_OPT(PGPSUBKEY)) { get_keyid (keyid, OPT_ARG(PGPSUBKEY)); } if (pgp_certfile != NULL && pgp_keyfile != NULL) { gnutls_openpgp_crt_t tmp_pgp_crt; ret = gnutls_load_file (pgp_certfile, &data); if (ret < 0) { fprintf (stderr, "*** Error loading PGP cert file.\n"); exit (1); } gnutls_openpgp_crt_init (&tmp_pgp_crt); ret = gnutls_pcert_import_openpgp_raw (&pgp_crt, &data, GNUTLS_OPENPGP_FMT_BASE64, HAVE_OPT(PGPSUBKEY)?keyid:NULL, 0); if (ret < 0) { fprintf (stderr, "*** Error loading PGP cert file: %s\n", gnutls_strerror (ret)); exit (1); } gnutls_free (data.data); ret = gnutls_privkey_init(&pgp_key); if (ret < 0) { fprintf (stderr, "*** Error initializing key: %s\n", gnutls_strerror (ret)); exit (1); } gnutls_privkey_set_pin_function(pgp_key, pin_callback, NULL); if (gnutls_url_is_supported (pgp_keyfile)) { ret = gnutls_privkey_import_url( pgp_key, pgp_keyfile, 0); if (ret < 0) { fprintf (stderr, "*** Error loading url: %s\n", gnutls_strerror (ret)); exit (1); } } else { ret = gnutls_load_file (pgp_keyfile, &data); if (ret < 0) { fprintf (stderr, "*** Error loading key file.\n"); exit (1); } if (HAVE_OPT(PGPSUBKEY)) ret = gnutls_privkey_import_openpgp_raw( pgp_key, &data, x509ctype, keyid, NULL); else ret = gnutls_privkey_import_openpgp_raw( pgp_key, &data, x509ctype, NULL, NULL); if (ret < 0) { fprintf (stderr, "*** Error loading url: %s\n", gnutls_strerror (ret)); exit (1); } gnutls_free(data.data); } fprintf (stdout, "Processed 1 client PGP certificate...\n"); } #endif }