/** * gnutls_privkey_sign_hash: * @signer: Holds the signer's key * @hash_algo: The hash algorithm used * @flags: Zero or one of %gnutls_privkey_flags_t * @hash_data: holds the data to be signed * @signature: will contain newly allocated signature * * This function will sign the given hashed data using a signature algorithm * supported by the private key. Signature algorithms are always used * together with a hash functions. Different hash functions may be * used for the RSA algorithm, but only SHA-XXX for the DSA keys. * * You may use gnutls_pubkey_get_preferred_hash_algorithm() to determine * the hash algorithm. * * Note that if %GNUTLS_PRIVKEY_SIGN_FLAG_TLS1_RSA flag is specified this function * will ignore @hash_algo and perform a raw PKCS1 signature. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 2.12.0 **/ int gnutls_privkey_sign_hash(gnutls_privkey_t signer, gnutls_digest_algorithm_t hash_algo, unsigned int flags, const gnutls_datum_t * hash_data, gnutls_datum_t * signature) { int ret; gnutls_datum_t digest; if (flags & GNUTLS_PRIVKEY_SIGN_FLAG_TLS1_RSA) return gnutls_privkey_sign_raw_data(signer, flags, hash_data, signature); digest.data = gnutls_malloc(hash_data->size); if (digest.data == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } digest.size = hash_data->size; memcpy(digest.data, hash_data->data, digest.size); ret = pk_prepare_hash(signer->pk_algorithm, mac_to_entry(hash_algo), &digest); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = gnutls_privkey_sign_raw_data(signer, flags, &digest, signature); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = 0; cleanup: _gnutls_free_datum(&digest); return ret; }
/** * gnutls_privkey_sign_data: * @signer: Holds the key * @hash: should be a digest algorithm * @flags: Zero or one of %gnutls_privkey_flags_t * @data: holds the data to be signed * @signature: will contain the signature allocate with gnutls_malloc() * * This function will sign the given data using a signature algorithm * supported by the private key. Signature algorithms are always used * together with a hash functions. Different hash functions may be * used for the RSA algorithm, but only the SHA family for the DSA keys. * * You may use gnutls_pubkey_get_preferred_hash_algorithm() to determine * the hash algorithm. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 2.12.0 **/ int gnutls_privkey_sign_data(gnutls_privkey_t signer, gnutls_digest_algorithm_t hash, unsigned int flags, const gnutls_datum_t * data, gnutls_datum_t * signature) { int ret; gnutls_datum_t digest; const mac_entry_st *me = mac_to_entry(hash); if (flags & GNUTLS_PRIVKEY_SIGN_FLAG_TLS1_RSA) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); ret = pk_hash_data(signer->pk_algorithm, me, NULL, data, &digest); if (ret < 0) { gnutls_assert(); return ret; } ret = pk_prepare_hash(signer->pk_algorithm, me, &digest); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = gnutls_privkey_sign_raw_data(signer, flags, &digest, signature); _gnutls_free_datum(&digest); if (ret < 0) { gnutls_assert(); return ret; } return 0; cleanup: _gnutls_free_datum(&digest); 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); } }
void doit(void) { gnutls_x509_privkey_t key; gnutls_x509_crt_t crt; gnutls_pubkey_t pubkey; gnutls_privkey_t privkey; gnutls_sign_algorithm_t sign_algo; gnutls_datum_t signature; gnutls_datum_t signature2; int ret; size_t i; global_init(); gnutls_global_set_log_function(tls_log_func); if (debug) gnutls_global_set_log_level(6); for (i = 0; i < sizeof(key_dat) / sizeof(key_dat[0]); i++) { if (debug) success("loop %d\n", (int) i); ret = gnutls_x509_privkey_init(&key); if (ret < 0) fail("gnutls_x509_privkey_init\n"); ret = gnutls_x509_privkey_import(key, &key_dat[i], GNUTLS_X509_FMT_PEM); if (ret < 0) fail("gnutls_x509_privkey_import\n"); ret = gnutls_pubkey_init(&pubkey); if (ret < 0) fail("gnutls_privkey_init\n"); ret = gnutls_privkey_init(&privkey); if (ret < 0) fail("gnutls_pubkey_init\n"); ret = gnutls_privkey_import_x509(privkey, key, 0); if (ret < 0) fail("gnutls_privkey_import_x509\n"); ret = gnutls_privkey_sign_hash(privkey, GNUTLS_DIG_SHA1, 0, &hash_data, &signature2); if (ret < 0) fail("gnutls_privkey_sign_hash\n"); ret = gnutls_privkey_sign_data(privkey, GNUTLS_DIG_SHA1, 0, &raw_data, &signature); if (ret < 0) fail("gnutls_x509_privkey_sign_hash\n"); ret = gnutls_x509_crt_init(&crt); if (ret < 0) fail("gnutls_x509_crt_init\n"); ret = gnutls_x509_crt_import(crt, &cert_dat[i], GNUTLS_X509_FMT_PEM); if (ret < 0) fail("gnutls_x509_crt_import\n"); ret = gnutls_pubkey_import_x509(pubkey, crt, 0); if (ret < 0) fail("gnutls_x509_pubkey_import\n"); ret = gnutls_x509_crt_get_signature_algorithm(crt); if (ret != GNUTLS_SIGN_RSA_SHA1) fail("gnutls_crt_get_signature_algorithm\n"); ret = gnutls_pubkey_verify_hash2(pubkey, GNUTLS_SIGN_RSA_SHA1, 0, &hash_data, &signature); if (ret < 0) fail("gnutls_x509_pubkey_verify_hash2\n"); ret = gnutls_pubkey_verify_hash2(pubkey, GNUTLS_SIGN_RSA_SHA1, 0, &hash_data, &signature2); if (ret < 0) fail("gnutls_x509_pubkey_verify_hash-1 (hashed data)\n"); /* should fail */ ret = gnutls_pubkey_verify_hash2(pubkey, GNUTLS_SIGN_RSA_SHA1, 0, &invalid_hash_data, &signature2); if (ret != GNUTLS_E_PK_SIG_VERIFY_FAILED) fail("gnutls_x509_pubkey_verify_hash-2 (hashed data)\n"); sign_algo = gnutls_pk_to_sign(gnutls_pubkey_get_pk_algorithm (pubkey, NULL), GNUTLS_DIG_SHA1); ret = gnutls_pubkey_verify_hash2(pubkey, sign_algo, 0, &hash_data, &signature2); if (ret < 0) fail("gnutls_x509_pubkey_verify_hash2-1 (hashed data)\n"); /* should fail */ ret = gnutls_pubkey_verify_hash2(pubkey, sign_algo, 0, &invalid_hash_data, &signature2); if (ret != GNUTLS_E_PK_SIG_VERIFY_FAILED) fail("gnutls_x509_pubkey_verify_hash2-2 (hashed data)\n"); /* test the raw interface */ gnutls_free(signature.data); signature.data = NULL; if (gnutls_pubkey_get_pk_algorithm(pubkey, NULL) == GNUTLS_PK_RSA) { ret = gnutls_privkey_sign_hash(privkey, GNUTLS_DIG_SHA1, GNUTLS_PRIVKEY_SIGN_FLAG_TLS1_RSA, &hash_data, &signature); if (ret < 0) fail("gnutls_privkey_sign_hash: %s\n", gnutls_strerror(ret)); sign_algo = gnutls_pk_to_sign (gnutls_pubkey_get_pk_algorithm(pubkey, NULL), GNUTLS_DIG_SHA1); ret = gnutls_pubkey_verify_hash2(pubkey, sign_algo, GNUTLS_PUBKEY_VERIFY_FLAG_TLS1_RSA, &hash_data, &signature); if (ret < 0) fail("gnutls_pubkey_verify_hash-3 (raw hashed data)\n"); gnutls_free(signature.data); /* test the legacy API */ ret = gnutls_privkey_sign_raw_data(privkey, 0, &hash_data, &signature); if (ret < 0) fail("gnutls_privkey_sign_raw_data: %s\n", gnutls_strerror(ret)); ret = gnutls_pubkey_verify_hash2(pubkey, sign_algo, GNUTLS_PUBKEY_VERIFY_FLAG_TLS1_RSA, &hash_data, &signature); if (ret < 0) fail("gnutls_pubkey_verify_hash-4 (legacy raw hashed data)\n"); } gnutls_free(signature.data); gnutls_free(signature2.data); gnutls_x509_privkey_deinit(key); gnutls_x509_crt_deinit(crt); gnutls_privkey_deinit(privkey); gnutls_pubkey_deinit(pubkey); } gnutls_global_deinit(); }
static int process_worker_packet(void *pool, int cfd, pid_t pid, sec_mod_st * sec, cmd_request_t cmd, uint8_t * buffer, size_t buffer_size) { unsigned i; gnutls_datum_t data, out; int ret; SecOpMsg *op; PROTOBUF_ALLOCATOR(pa, pool); seclog(sec, LOG_DEBUG, "cmd [size=%d] %s\n", (int)buffer_size, cmd_request_to_str(cmd)); data.data = buffer; data.size = buffer_size; switch (cmd) { case CMD_SEC_SIGN: case CMD_SEC_DECRYPT: op = sec_op_msg__unpack(&pa, data.size, data.data); if (op == NULL) { seclog(sec, LOG_INFO, "error unpacking sec op\n"); return -1; } i = op->key_idx; if (op->has_key_idx == 0 || i >= sec->key_size) { seclog(sec, LOG_INFO, "received out-of-bounds key index (%d)", i); return -1; } data.data = op->data.data; data.size = op->data.len; if (cmd == CMD_SEC_DECRYPT) { ret = gnutls_privkey_decrypt_data(sec->key[i], 0, &data, &out); } else { #if GNUTLS_VERSION_NUMBER >= 0x030200 ret = gnutls_privkey_sign_hash(sec->key[i], 0, GNUTLS_PRIVKEY_SIGN_FLAG_TLS1_RSA, &data, &out); #else ret = gnutls_privkey_sign_raw_data(sec->key[i], 0, &data, &out); #endif } sec_op_msg__free_unpacked(op, &pa); if (ret < 0) { seclog(sec, LOG_INFO, "error in crypto operation: %s", gnutls_strerror(ret)); return -1; } ret = handle_op(pool, cfd, sec, cmd, out.data, out.size); gnutls_free(out.data); return ret; case CMD_SEC_CLI_STATS:{ CliStatsMsg *tmsg; tmsg = cli_stats_msg__unpack(&pa, data.size, data.data); if (tmsg == NULL) { seclog(sec, LOG_ERR, "error unpacking data"); return -1; } ret = handle_sec_auth_stats_cmd(sec, tmsg, pid); cli_stats_msg__free_unpacked(tmsg, &pa); return ret; } break; case CMD_SEC_AUTH_INIT:{ SecAuthInitMsg *auth_init; auth_init = sec_auth_init_msg__unpack(&pa, data.size, data.data); if (auth_init == NULL) { seclog(sec, LOG_INFO, "error unpacking auth init\n"); return -1; } ret = handle_sec_auth_init(cfd, sec, auth_init, pid); sec_auth_init_msg__free_unpacked(auth_init, &pa); return ret; } case CMD_SEC_AUTH_CONT:{ SecAuthContMsg *auth_cont; auth_cont = sec_auth_cont_msg__unpack(&pa, data.size, data.data); if (auth_cont == NULL) { seclog(sec, LOG_INFO, "error unpacking auth cont\n"); return -1; } ret = handle_sec_auth_cont(cfd, sec, auth_cont); sec_auth_cont_msg__free_unpacked(auth_cont, &pa); return ret; } case RESUME_STORE_REQ:{ SessionResumeStoreReqMsg *smsg; smsg = session_resume_store_req_msg__unpack(&pa, buffer_size, buffer); if (smsg == NULL) { seclog(sec, LOG_ERR, "error unpacking data"); return ERR_BAD_COMMAND; } ret = handle_resume_store_req(sec, smsg); /* zeroize the data */ safe_memset(buffer, 0, buffer_size); safe_memset(smsg->session_data.data, 0, smsg->session_data.len); session_resume_store_req_msg__free_unpacked(smsg, &pa); if (ret < 0) { seclog(sec, LOG_DEBUG, "could not store resumption data"); } } break; case RESUME_DELETE_REQ:{ SessionResumeFetchMsg *fmsg; fmsg = session_resume_fetch_msg__unpack(&pa, buffer_size, buffer); if (fmsg == NULL) { seclog(sec, LOG_ERR, "error unpacking data"); return ERR_BAD_COMMAND; } ret = handle_resume_delete_req(sec, fmsg); session_resume_fetch_msg__free_unpacked(fmsg, &pa); if (ret < 0) { seclog(sec, LOG_DEBUG, "could not delete resumption data."); } } break; case RESUME_FETCH_REQ:{ SessionResumeReplyMsg msg = SESSION_RESUME_REPLY_MSG__INIT; SessionResumeFetchMsg *fmsg; /* FIXME: rate limit that */ fmsg = session_resume_fetch_msg__unpack(&pa, buffer_size, buffer); if (fmsg == NULL) { seclog(sec, LOG_ERR, "error unpacking data"); return ERR_BAD_COMMAND; } ret = handle_resume_fetch_req(sec, fmsg, &msg); session_resume_fetch_msg__free_unpacked(fmsg, &pa); if (ret < 0) { msg.reply = SESSION_RESUME_REPLY_MSG__RESUME__REP__FAILED; seclog(sec, LOG_DEBUG, "could not fetch resumption data."); } else { msg.reply = SESSION_RESUME_REPLY_MSG__RESUME__REP__OK; } ret = send_msg(pool, cfd, RESUME_FETCH_REP, &msg, (pack_size_func) session_resume_reply_msg__get_packed_size, (pack_func) session_resume_reply_msg__pack); if (ret < 0) { seclog(sec, LOG_ERR, "could not send reply cmd %d.", (unsigned)cmd); return ERR_BAD_COMMAND; } } break; default: seclog(sec, LOG_WARNING, "unknown type 0x%.2x", cmd); return -1; } return 0; }
/* This will create a PKCS1 or DSA signature, as defined in the TLS protocol. * Cert is the certificate of the corresponding private key. It is only checked if * it supports signing. */ static int sign_tls_hash(gnutls_session_t session, const mac_entry_st * hash_algo, gnutls_pcert_st * cert, gnutls_privkey_t pkey, const gnutls_datum_t * hash_concat, gnutls_datum_t * signature) { const version_entry_st *ver = get_version(session); unsigned int key_usage = 0; /* If our certificate supports signing */ if (cert != NULL) { gnutls_pubkey_get_key_usage(cert->pubkey, &key_usage); if (key_usage != 0) if (!(key_usage & GNUTLS_KEY_DIGITAL_SIGNATURE)) { gnutls_assert(); _gnutls_audit_log(session, "Peer's certificate does not allow digital signatures. Key usage violation detected (ignored).\n"); } /* External signing. Deprecated. To be removed. */ if (!pkey) { int ret; if (!session->internals.sign_func) return gnutls_assert_val (GNUTLS_E_INSUFFICIENT_CREDENTIALS); if (!_gnutls_version_has_selectable_sighash(ver)) return (*session->internals.sign_func) (session, session->internals.sign_func_userdata, cert->type, &cert->cert, hash_concat, signature); else { gnutls_datum_t digest; ret = _gnutls_set_datum(&digest, hash_concat->data, hash_concat->size); if (ret < 0) return gnutls_assert_val(ret); ret = pk_prepare_hash (gnutls_pubkey_get_pk_algorithm (cert->pubkey, NULL), hash_algo, &digest); if (ret < 0) { gnutls_assert(); goto es_cleanup; } ret = (*session->internals.sign_func) (session, session->internals.sign_func_userdata, cert->type, &cert->cert, &digest, signature); es_cleanup: gnutls_free(digest.data); return ret; } } } if (!_gnutls_version_has_selectable_sighash(ver)) return gnutls_privkey_sign_raw_data(pkey, 0, hash_concat, signature); else return gnutls_privkey_sign_hash(pkey, (gnutls_digest_algorithm_t)hash_algo->id, 0, hash_concat, signature); }