/* This function will set the auth info structure in the key * structure. * If allow change is !=0 then this will allow changing the auth * info structure to a different type. */ int _gnutls_auth_info_set (gnutls_session_t session, gnutls_credentials_type_t type, int size, int allow_change) { if (session->key->auth_info == NULL) { session->key->auth_info = gnutls_calloc (1, size); if (session->key->auth_info == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } session->key->auth_info_type = type; session->key->auth_info_size = size; } else { if (allow_change == 0) { /* If the credentials for the current authentication scheme, * are not the one we want to set, then it's an error. * This may happen if a rehandshake is performed an the * ciphersuite which is negotiated has different authentication * schema. */ if (gnutls_auth_get_type (session) != session->key->auth_info_type) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } } else { /* The new behaviour: Here we reallocate the auth info structure * in order to be able to negotiate different authentication * types. Ie. perform an auth_anon and then authenticate again using a * certificate (in order to prevent revealing the certificate's contents, * to passive eavesdropers. */ if (gnutls_auth_get_type (session) != session->key->auth_info_type) { _gnutls_free_auth_info (session); session->key->auth_info = calloc (1, size); if (session->key->auth_info == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } session->key->auth_info_type = type; session->key->auth_info_size = size; } } } return 0; }
const char *dtls_gnutls_get_cipher(struct conn *conn, char *dst) { struct dtls_gnutls_data * d; const char *comp, *cipher, *mac, *proto, *kxname, *auth; gnutls_kx_algorithm_t kx; gnutls_credentials_type_t cred; if (!conn->dtls_data){ sprintf(dst, "%s","None"); return dst; } d = (struct dtls_gnutls_data*)conn->dtls_data; if ( !d->session ){ sprintf(dst, "%s","None"); return dst; } kx = gnutls_kx_get(d->session); kxname = gnutls_kx_get_name(kx); cred = gnutls_auth_get_type(d->session); proto = gnutls_protocol_get_name(gnutls_protocol_get_version(d->session)); comp = gnutls_compression_get_name(gnutls_compression_get(d->session)); cipher = gnutls_cipher_get_name(gnutls_cipher_get(d->session)); mac = gnutls_mac_get_name(gnutls_mac_get(d->session)); sprintf(dst,"cipher: %s/%s/%s/%s/%s",proto,kxname,cipher,mac,comp); return dst; }
/* This function will log some details of the given session. */ static void logtlsinfo (gnutls_session_t session) { gnutls_credentials_type_t cred; const char *protocol = gnutls_protocol_get_name (gnutls_protocol_get_version (session)); gnutls_kx_algorithm_t kx = gnutls_kx_get (session); const char *keyexchange = gnutls_kx_get_name (kx); const char *certtype = gnutls_certificate_type_get_name (gnutls_certificate_type_get (session)); const char *cipher = gnutls_cipher_get_name (gnutls_cipher_get (session)); const char *mac = gnutls_mac_get_name (gnutls_mac_get (session)); const char *compression = gnutls_compression_get_name (gnutls_compression_get (session)); int resumedp = gnutls_session_is_resumed (session); /* This message can arguably belong to LOG_AUTH. */ syslog (LOG_INFO, "TLS handshake negotiated protocol `%s', " "key exchange `%s', certficate type `%s', cipher `%s', " "mac `%s', compression `%s', %s", protocol ? protocol : "N/A", keyexchange ? keyexchange : "N/A", certtype ? certtype : "N/A", cipher ? cipher : "N/A", mac ? mac : "N/A", compression ? compression : "N/A", resumedp ? "resumed session" : "session not resumed"); cred = gnutls_auth_get_type (session); switch (cred) { case GNUTLS_CRD_ANON: syslog (LOG_INFO | LOG_DAEMON, "TLS anonymous authentication with %d bit Diffie-Hellman", gnutls_dh_get_prime_bits (session)); break; case GNUTLS_CRD_CERTIFICATE: if (kx == GNUTLS_KX_DHE_RSA || kx == GNUTLS_KX_DHE_DSS) syslog (LOG_INFO | LOG_DAEMON, "TLS certificate authentication with %d bits " "ephemeral Diffie-Hellman", gnutls_dh_get_prime_bits (session)); logcertinfo (session); break; case GNUTLS_CRD_SRP: case GNUTLS_CRD_PSK: case GNUTLS_CRD_IA: default: syslog (LOG_ERR | LOG_DAEMON, "Unknown TLS authentication (%d)", cred); break; } }
/** * gnutls_dh_get_group: * @session: is a gnutls session * @raw_gen: will hold the generator. * @raw_prime: will hold the prime. * * This function will return the group parameters used in the last * Diffie-Hellman key exchange with the peer. These are the prime and * the generator used. This function should be used for both * anonymous and ephemeral Diffie-Hellman. The output parameters must * be freed with gnutls_free(). * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise * an error code is returned. **/ int gnutls_dh_get_group(gnutls_session_t session, gnutls_datum_t * raw_gen, gnutls_datum_t * raw_prime) { dh_info_st *dh; int ret; anon_auth_info_t anon_info; cert_auth_info_t cert_info; psk_auth_info_t psk_info; switch (gnutls_auth_get_type(session)) { case GNUTLS_CRD_ANON: anon_info = _gnutls_get_auth_info(session, GNUTLS_CRD_ANON); if (anon_info == NULL) return GNUTLS_E_INTERNAL_ERROR; dh = &anon_info->dh; break; case GNUTLS_CRD_PSK: psk_info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK); if (psk_info == NULL) return GNUTLS_E_INTERNAL_ERROR; dh = &psk_info->dh; break; case GNUTLS_CRD_CERTIFICATE: cert_info = _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE); if (cert_info == NULL) return GNUTLS_E_INTERNAL_ERROR; dh = &cert_info->dh; break; default: gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } ret = _gnutls_set_datum(raw_prime, dh->prime.data, dh->prime.size); if (ret < 0) { gnutls_assert(); return ret; } ret = _gnutls_set_datum(raw_gen, dh->generator.data, dh->generator.size); if (ret < 0) { gnutls_assert(); _gnutls_free_datum(raw_prime); return ret; } return 0; }
static int handle_client_connection(const char *srcinfo, prelude_client_profile_t *cp, prelude_io_t *fd, gnutls_x509_privkey_t key, gnutls_x509_crt_t cacrt, gnutls_x509_crt_t crt) { gnutls_session_t session; session = new_tls_session(prelude_io_get_fd(fd)); if ( ! session ) return -1; prelude_io_set_tls_io(fd, session); if ( gnutls_auth_get_type(session) == GNUTLS_CRD_ANON && anon_check_passwd(fd) < 0 ) return -1; return tls_handle_certificate_request(srcinfo, cp, fd, key, cacrt, crt); }
/** * gnutls_dh_get_prime_bits: * @session: is a gnutls session * * This function will return the bits of the prime used in the last * Diffie-Hellman key exchange with the peer. Should be used for both * anonymous and ephemeral Diffie-Hellman. Note that some ciphers, * like RSA and DSA without DHE, do not use a Diffie-Hellman key * exchange, and then this function will return 0. * * Returns: The Diffie-Hellman bit strength is returned, or 0 if no * Diffie-Hellman key exchange was done, or a negative error code on * failure. **/ int gnutls_dh_get_prime_bits(gnutls_session_t session) { dh_info_st *dh; switch (gnutls_auth_get_type(session)) { case GNUTLS_CRD_ANON: { anon_auth_info_t info; info = _gnutls_get_auth_info(session, GNUTLS_CRD_ANON); if (info == NULL) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); dh = &info->dh; break; } case GNUTLS_CRD_PSK: { psk_auth_info_t info; info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK); if (info == NULL) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); dh = &info->dh; break; } case GNUTLS_CRD_CERTIFICATE: { cert_auth_info_t info; info = _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE); if (info == NULL) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); dh = &info->dh; break; } default: gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } if(dh->prime.size == 0) return 0; return mpi_buf2bits(&dh->prime); }
/** * gnutls_dh_get_pubkey: * @session: is a gnutls session * @raw_key: will hold the public key. * * This function will return the peer's public key used in the last * Diffie-Hellman key exchange. This function should be used for both * anonymous and ephemeral Diffie-Hellman. The output parameters must * be freed with gnutls_free(). * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise * an error code is returned. **/ int gnutls_dh_get_pubkey(gnutls_session_t session, gnutls_datum_t * raw_key) { dh_info_st *dh; anon_auth_info_t anon_info; cert_auth_info_t cert_info; cert_auth_info_t psk_info; switch (gnutls_auth_get_type(session)) { case GNUTLS_CRD_ANON: { anon_info = _gnutls_get_auth_info(session, GNUTLS_CRD_ANON); if (anon_info == NULL) return GNUTLS_E_INTERNAL_ERROR; dh = &anon_info->dh; break; } case GNUTLS_CRD_PSK: { psk_info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK); if (psk_info == NULL) return GNUTLS_E_INTERNAL_ERROR; dh = &psk_info->dh; break; } case GNUTLS_CRD_CERTIFICATE: { cert_info = _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE); if (cert_info == NULL) return GNUTLS_E_INTERNAL_ERROR; dh = &cert_info->dh; break; } default: gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } return _gnutls_set_datum(raw_key, dh->public_key.data, dh->public_key.size); }
/** * gnutls_dh_get_secret_bits: * @session: is a gnutls session * * This function will return the bits used in the last Diffie-Hellman * key exchange with the peer. Should be used for both anonymous and * ephemeral Diffie-Hellman. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise * an error code is returned. **/ int gnutls_dh_get_secret_bits(gnutls_session_t session) { switch (gnutls_auth_get_type(session)) { case GNUTLS_CRD_ANON: { anon_auth_info_t info; info = _gnutls_get_auth_info(session, GNUTLS_CRD_ANON); if (info == NULL) return GNUTLS_E_INTERNAL_ERROR; return info->dh.secret_bits; } case GNUTLS_CRD_PSK: { psk_auth_info_t info; info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK); if (info == NULL) return GNUTLS_E_INTERNAL_ERROR; return info->dh.secret_bits; } case GNUTLS_CRD_CERTIFICATE: { cert_auth_info_t info; info = _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE); if (info == NULL) return GNUTLS_E_INTERNAL_ERROR; return info->dh.secret_bits; } default: gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } }
static int tls_check_certificate (CONNECTION* conn) { tlssockdata *data = conn->sockdata; gnutls_session state = data->state; const gnutls_datum *cert_list; unsigned int cert_list_size = 0; gnutls_certificate_status certstat; int certerr, i, rc; if (gnutls_auth_get_type (state) != GNUTLS_CRD_CERTIFICATE) { mutt_error (_("Unable to get certificate from peer")); mutt_sleep (2); return 0; } certstat = gnutls_certificate_verify_peers (state); if (certstat == GNUTLS_E_NO_CERTIFICATE_FOUND) { mutt_error (_("Unable to get certificate from peer")); mutt_sleep (2); return 0; } if (certstat < 0) { mutt_error (_("Certificate verification error (%s)"), gnutls_strerror (certstat)); mutt_sleep (2); return 0; } /* We only support X.509 certificates (not OpenPGP) at the moment */ if (gnutls_certificate_type_get (state) != GNUTLS_CRT_X509) { mutt_error (_("Certificate is not X.509")); mutt_sleep (2); return 0; } cert_list = gnutls_certificate_get_peers (state, &cert_list_size); if (!cert_list) { mutt_error (_("Unable to get certificate from peer")); mutt_sleep (2); return 0; } /* first check chain noninteractively */ for (i = 0; i < cert_list_size; i++) { rc = tls_check_preauth(&cert_list[i], certstat, conn->account.host, !i, &certerr); if (!rc) return 1; } /* then check interactively, starting from chain root */ for (i = cert_list_size - 1; i >= 0; i--) { rc = tls_check_one_certificate (&cert_list[i], certstat, conn->account.host, i, cert_list_size); if (rc) return rc; } return 0; }
/* This function will print some details of the * given session. */ int print_info (gnutls_session_t session) { const char *tmp; gnutls_credentials_type_t cred; gnutls_kx_algorithm_t kx; /* print the key exchange's algorithm name */ kx = gnutls_kx_get (session); tmp = gnutls_kx_get_name (kx); printf ("- Key Exchange: %s\n", tmp); /* Check the authentication type used and switch * to the appropriate. */ cred = gnutls_auth_get_type (session); switch (cred) { case GNUTLS_CRD_IA: printf ("- TLS/IA session\n"); break; #ifdef ENABLE_SRP case GNUTLS_CRD_SRP: printf ("- SRP session with username %s\n", gnutls_srp_server_get_username (session)); break; #endif case GNUTLS_CRD_PSK: /* This returns NULL in server side. */ if (gnutls_psk_client_get_hint (session) != NULL) printf ("- PSK authentication. PSK hint '%s'\n", gnutls_psk_client_get_hint (session)); /* This returns NULL in client side. */ if (gnutls_psk_server_get_username (session) != NULL) printf ("- PSK authentication. Connected as '%s'\n", gnutls_psk_server_get_username (session)); break; case GNUTLS_CRD_ANON: /* anonymous authentication */ printf ("- Anonymous DH using prime of %d bits\n", gnutls_dh_get_prime_bits (session)); break; case GNUTLS_CRD_CERTIFICATE: /* certificate authentication */ /* Check if we have been using ephemeral Diffie-Hellman. */ if (kx == GNUTLS_KX_DHE_RSA || kx == GNUTLS_KX_DHE_DSS) { printf ("\n- Ephemeral DH using prime of %d bits\n", gnutls_dh_get_prime_bits (session)); } /* if the certificate list is available, then * print some information about it. */ print_x509_certificate_info (session); } /* switch */ /* print the protocol's name (ie TLS 1.0) */ tmp = gnutls_protocol_get_name (gnutls_protocol_get_version (session)); printf ("- Protocol: %s\n", tmp); /* print the certificate type of the peer. * ie X.509 */ tmp = gnutls_certificate_type_get_name (gnutls_certificate_type_get (session)); printf ("- Certificate Type: %s\n", tmp); /* print the compression algorithm (if any) */ tmp = gnutls_compression_get_name (gnutls_compression_get (session)); printf ("- Compression: %s\n", tmp); /* print the name of the cipher used. * ie 3DES. */ tmp = gnutls_cipher_get_name (gnutls_cipher_get (session)); printf ("- Cipher: %s\n", tmp); /* Print the MAC algorithms name. * ie SHA1 */ tmp = gnutls_mac_get_name (gnutls_mac_get (session)); printf ("- MAC: %s\n", tmp); return 0; }
gnutls_credentials_type_t session::get_auth_type () const { return gnutls_auth_get_type (s); }
void gtlsGeneric::logSessionInfo(LogWrapperType _logwrapper, gnutls_session_t _session) { const char *tmp; gnutls_credentials_type_t cred; gnutls_kx_algorithm_t kx; // print the key exchange's algorithm name kx = gnutls_kx_get(_session); tmp = gnutls_kx_get_name(kx); BTG_NOTICE(_logwrapper, "- Key Exchange: " << tmp); // Check the authentication type used and switch // to the appropriate. cred = gnutls_auth_get_type(_session); switch (cred) { case GNUTLS_CRD_SRP: { BTG_NOTICE(_logwrapper, "- SRP session"); break; } case GNUTLS_CRD_ANON: { BTG_NOTICE(_logwrapper, "- Anonymous DH using prime of " << gnutls_dh_get_prime_bits (_session) << " bits"); break; } case GNUTLS_CRD_CERTIFICATE: { // Check if we have been using ephemeral Diffie Hellman. if (kx == GNUTLS_KX_DHE_RSA || kx == GNUTLS_KX_DHE_DSS) { BTG_NOTICE(_logwrapper, "- Ephemeral DH using prime of " << gnutls_dh_get_prime_bits(_session) << " bits"); } /* if the certificate list is available, then * print some information about it. */ gtlsGeneric::logX509CertificateInfo(_logwrapper, _session); break; } default: { BTG_NOTICE(_logwrapper, "Unknown cred."); } } /* print the protocol's name (ie TLS 1.0) */ tmp = gnutls_protocol_get_name(gnutls_protocol_get_version(_session)); BTG_NOTICE(_logwrapper, "- Protocol: " << tmp); /* print the certificate type of the peer. * ie X.509 */ tmp = gnutls_certificate_type_get_name(gnutls_certificate_type_get(_session)); BTG_NOTICE(_logwrapper, "- Certificate Type: " << tmp); /* print the compression algorithm (if any) */ tmp = gnutls_compression_get_name(gnutls_compression_get(_session)); BTG_NOTICE(_logwrapper, "- Compression: " << tmp); /* print the name of the cipher used. * ie 3DES. */ tmp = gnutls_cipher_get_name(gnutls_cipher_get(_session)); BTG_NOTICE(_logwrapper, "- Cipher: " << tmp); /* Print the MAC algorithms name. * ie SHA1 */ tmp = gnutls_mac_get_name(gnutls_mac_get(_session)); BTG_NOTICE(_logwrapper, "- MAC: " << tmp); }
/** * @brief Get info pertaining to a socket. * @naslfn{get_sock_info} * * This function is used to retrieve various information about an * active socket. It requires the NASL socket number and a string to * select the information to retrieve. * * Supported keywords are: * * - @a dport Return the destination port. This is an integer. NOTE: * Not yet implemented. * * - @a sport Return the source port. This is an integer. NOTE: Not * yet implemented. * * - @a encaps Return the encapsulation of the socket. Example * output: "TLScustom". * * - @a tls-proto Return a string with the actual TLS protocol in use. * n/a" is returned if no SSL/TLS session is active. Example * output: "TLSv1". * * - @a tls-kx Return a string describing the key exchange algorithm. * Example output: "RSA". * * - @a tls-certtype Return the type of the certificate in use by the * session. Example output: "X.509" * * - @a tls-cipher Return the cipher algorithm in use by the session; * Example output: "AES-256-CBC". * * - @a tls-mac Return the message authentication algorithms used by * the session. Example output: "SHA1". * * - @a tls-comp Return the compression algorithms in use by the * session. Example output: "DEFLATE". * * - @a tls-auth Return the peer's authentication type. Example * output: "CERT". * * - @a tls-cert Return the peer's certificates for an SSL or TLS * connection. This is an array of binary strings or NULL if no * certificate is known. * * @nasluparam * * - A NASL socket * * - A string keyword; see above. * * @naslnparam * * - @a asstring If true return a human readable string instead of * an integer. Used only with these keywords: encaps. * * @naslret An integer or a string or NULL on error. * * @param[in] lexic Lexical context of the NASL interpreter. * * @return A tree cell. */ tree_cell * nasl_get_sock_info (lex_ctxt * lexic) { int sock; int type; int err; const char *keyword, *s; tree_cell *retc; int as_string; int transport; gnutls_session_t tls_session; char *strval; int intval; sock = get_int_var_by_num (lexic, 0, -1); if (sock <= 0) { nasl_perror (lexic, "error: socket %d is not valid\n"); return NULL; } keyword = get_str_var_by_num (lexic, 1); if (!keyword || !((type = get_var_type_by_num (lexic, 1)) == VAR2_STRING || type == VAR2_DATA)) { nasl_perror (lexic, "error: second argument is not of type string\n"); return NULL; } as_string = !!get_int_local_var_by_name (lexic, "asstring", 0); transport = 0; strval = NULL; intval = 0; retc = FAKE_CELL; /* Dummy value to detect retc == NULL. */ { void *tmp = NULL; err = get_sock_infos (sock, &transport, &tmp); tls_session = tmp; } if (err) { nasl_perror (lexic, "error retrieving infos for socket %d: %s\n", sock, strerror (err)); retc = NULL; } else if (!strcmp (keyword, "encaps")) { if (as_string) strval = estrdup (get_encaps_name (transport)); else intval = transport; } else if (!strcmp (keyword, "tls-proto")) { if (!tls_session) s = "n/a"; else s = gnutls_protocol_get_name (gnutls_protocol_get_version (tls_session)); strval = estrdup (s?s:"[?]"); } else if (!strcmp (keyword, "tls-kx")) { if (!tls_session) s = "n/a"; else s = gnutls_kx_get_name (gnutls_kx_get (tls_session)); strval = estrdup (s?s:""); } else if (!strcmp (keyword, "tls-certtype")) { if (!tls_session) s = "n/a"; else s = gnutls_certificate_type_get_name (gnutls_certificate_type_get (tls_session)); strval = estrdup (s?s:""); } else if (!strcmp (keyword, "tls-cipher")) { if (!tls_session) s = "n/a"; else s = gnutls_cipher_get_name (gnutls_cipher_get (tls_session)); strval = estrdup (s?s:""); } else if (!strcmp (keyword, "tls-mac")) { if (!tls_session) s = "n/a"; else s = gnutls_mac_get_name (gnutls_mac_get (tls_session)); strval = estrdup (s?s:""); } else if (!strcmp (keyword, "tls-comp")) { if (!tls_session) s = "n/a"; else s = gnutls_compression_get_name (gnutls_compression_get (tls_session)); strval = estrdup (s?s:""); } else if (!strcmp (keyword, "tls-auth")) { if (!tls_session) s = "n/a"; else { switch (gnutls_auth_get_type (tls_session)) { case GNUTLS_CRD_ANON: s = "ANON"; break; case GNUTLS_CRD_CERTIFICATE: s = "CERT"; break; case GNUTLS_CRD_PSK: s = "PSK"; break; case GNUTLS_CRD_SRP: s = "SRP"; break; default: s = "[?]"; break; } } strval = estrdup (s?s:""); } else if (!strcmp (keyword, "tls-cert")) { /* We only support X.509 for now. GNUTLS also allows for OpenPGP, but we are not prepared for that. */ if (!tls_session || gnutls_certificate_type_get (tls_session) != GNUTLS_CRT_X509) s = "n/a"; else { const gnutls_datum_t *list; unsigned int nlist = 0; int i; nasl_array *a; anon_nasl_var v; list = gnutls_certificate_get_peers (tls_session, &nlist); if (!list) retc = NULL; /* No certificate or other error. */ else { retc = alloc_tree_cell (0, NULL); retc->type = DYN_ARRAY; retc->x.ref_val = a = emalloc (sizeof *a); for (i=0; i < nlist; i++) { memset (&v, 0, sizeof v); v.var_type = VAR2_DATA; v.v.v_str.s_val = list[i].data; v.v.v_str.s_siz = list[i].size; add_var_to_list (a, i, &v); } } } } else { nasl_perror (lexic, "unknown keyword '%s'\n", keyword); retc = NULL; } if (!retc) ; else if (retc != FAKE_CELL) ; /* Already allocated. */ else if (strval) { retc = alloc_typed_cell (CONST_STR); retc->x.str_val = strval; retc->size = strlen (strval); } else { retc = alloc_typed_cell (CONST_INT); retc->x.i_val = intval; } return retc; }
/* Since auth_info structures contain malloced data, this function * is required in order to pack these structures in a vector in * order to store them to the DB. * * packed_session will contain the session data. * * The data will be in a platform independent format. */ int _gnutls_session_pack (gnutls_session_t session, gnutls_datum_t * packed_session) { int ret; if (packed_session == NULL) { gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } switch (gnutls_auth_get_type (session)) { #ifdef ENABLE_SRP case GNUTLS_CRD_SRP: ret = pack_srp_auth_info (session, packed_session); if (ret < 0) { gnutls_assert (); return ret; } break; #endif #ifdef ENABLE_PSK case GNUTLS_CRD_PSK: ret = pack_psk_auth_info (session, packed_session); if (ret < 0) { gnutls_assert (); return ret; } break; #endif #ifdef ENABLE_ANON case GNUTLS_CRD_ANON: ret = pack_anon_auth_info (session, packed_session); if (ret < 0) { gnutls_assert (); return ret; } break; #endif case GNUTLS_CRD_CERTIFICATE: ret = pack_certificate_auth_info (session, packed_session); if (ret < 0) { gnutls_assert (); return ret; } break; default: return GNUTLS_E_INTERNAL_ERROR; } /* Auth_info structures copied. Now copy security_parameters_st. * packed_session must have allocated space for the security parameters. */ ret = pack_security_parameters (session, packed_session); if (ret < 0) { gnutls_assert (); _gnutls_free_datum (packed_session); return ret; } return 0; }
int print_info (gnutls_session_t session, const char *hostname, int insecure) { const char *tmp; gnutls_credentials_type_t cred; gnutls_kx_algorithm_t kx; /* print the key exchange's algorithm name */ kx = gnutls_kx_get (session); cred = gnutls_auth_get_type (session); switch (cred) { #ifdef ENABLE_ANON case GNUTLS_CRD_ANON: print_dh_info (session, "Anonymous "); break; #endif #ifdef ENABLE_SRP case GNUTLS_CRD_SRP: /* This should be only called in server * side. */ if (gnutls_srp_server_get_username (session) != NULL) printf ("- SRP authentication. Connected as '%s'\n", gnutls_srp_server_get_username (session)); break; #endif #ifdef ENABLE_PSK case GNUTLS_CRD_PSK: /* This returns NULL in server side. */ if (gnutls_psk_client_get_hint (session) != NULL) printf ("- PSK authentication. PSK hint '%s'\n", gnutls_psk_client_get_hint (session)); /* This returns NULL in client side. */ if (gnutls_psk_server_get_username (session) != NULL) printf ("- PSK authentication. Connected as '%s'\n", gnutls_psk_server_get_username (session)); if (kx == GNUTLS_KX_DHE_PSK) print_dh_info (session, "Ephemeral "); break; #endif case GNUTLS_CRD_IA: printf ("- TLS/IA authentication\n"); break; case GNUTLS_CRD_CERTIFICATE: { char dns[256]; size_t dns_size = sizeof (dns); unsigned int type; /* This fails in client side */ if (gnutls_server_name_get (session, dns, &dns_size, &type, 0) == 0) { printf ("- Given server name[%d]: %s\n", type, dns); } } if (kx == GNUTLS_KX_DHE_RSA || kx == GNUTLS_KX_DHE_DSS) print_dh_info (session, "Ephemeral "); print_cert_info (session, hostname, insecure); print_cert_vrfy (session); } tmp = SU (gnutls_protocol_get_name (gnutls_protocol_get_version (session))); printf ("- Version: %s\n", tmp); tmp = SU (gnutls_kx_get_name (kx)); printf ("- Key Exchange: %s\n", tmp); tmp = SU (gnutls_cipher_get_name (gnutls_cipher_get (session))); printf ("- Cipher: %s\n", tmp); tmp = SU (gnutls_mac_get_name (gnutls_mac_get (session))); printf ("- MAC: %s\n", tmp); tmp = SU (gnutls_compression_get_name (gnutls_compression_get (session))); printf ("- Compression: %s\n", tmp); if (verbose) { char id[32]; size_t id_size = sizeof (id); gnutls_session_get_id (session, id, &id_size); printf ("- Session ID: %s\n", raw_to_string (id, id_size)); } fflush (stdout); return 0; }
static int tls_check_certificate (CONNECTION* conn) { tlssockdata *data = conn->sockdata; gnutls_session state = data->state; const gnutls_datum *cert_list; unsigned int cert_list_size = 0; gnutls_certificate_status certstat; int certerr, i, preauthrc, savedcert, rc = 0; int rcpeer = -1; /* the result of tls_check_preauth() on the peer's EE cert */ if (gnutls_auth_get_type (state) != GNUTLS_CRD_CERTIFICATE) { mutt_error (_("Unable to get certificate from peer")); mutt_sleep (2); return 0; } certstat = tls_verify_peers (state); cert_list = gnutls_certificate_get_peers (state, &cert_list_size); if (!cert_list) { mutt_error (_("Unable to get certificate from peer")); mutt_sleep (2); return 0; } /* tls_verify_peers doesn't check hostname or expiration, so walk * from most specific to least checking these. If we see a saved certificate, * its status short-circuits the remaining checks. */ preauthrc = 0; for (i = 0; i < cert_list_size; i++) { rc = tls_check_preauth(&cert_list[i], certstat, conn->account.host, i, &certerr, &savedcert); preauthrc += rc; if (i == 0) { /* This is the peer's end-entity X.509 certificate. Stash the result * to check later in this function. */ rcpeer = rc; } if (savedcert) { if (!preauthrc) return 1; else break; } } /* then check interactively, starting from chain root */ for (i = cert_list_size - 1; i >= 0; i--) { rc = tls_check_one_certificate (&cert_list[i], certstat, conn->account.host, i, cert_list_size); /* add signers to trust set, then reverify */ if (i && rc) { rc = gnutls_certificate_set_x509_trust_mem (data->xcred, &cert_list[i], GNUTLS_X509_FMT_DER); if (rc != 1) dprint (1, (debugfile, "error trusting certificate %d: %d\n", i, rc)); certstat = tls_verify_peers (state); /* If the cert chain now verifies, and the peer's cert was otherwise * valid (rcpeer==0), we are done. */ if (!certstat && !rcpeer) return 1; } } return rc; }
/* Since auth_info structures contain malloced data, this function * is required in order to pack these structures in a vector in * order to store them to the DB. * * packed_session will contain the session data. * * The data will be in a platform independent format. */ int _gnutls_session_pack (gnutls_session_t session, gnutls_datum_t * packed_session) { int ret; gnutls_buffer_st sb; opaque id; if (packed_session == NULL) { gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } _gnutls_buffer_init (&sb); id = gnutls_auth_get_type (session); BUFFER_APPEND (&sb, &id, 1); switch (id) { #ifdef ENABLE_SRP case GNUTLS_CRD_SRP: ret = pack_srp_auth_info (session, &sb); if (ret < 0) { gnutls_assert (); return ret; } break; #endif #ifdef ENABLE_PSK case GNUTLS_CRD_PSK: ret = pack_psk_auth_info (session, &sb); if (ret < 0) { gnutls_assert (); return ret; } break; #endif #ifdef ENABLE_ANON case GNUTLS_CRD_ANON: ret = pack_anon_auth_info (session, &sb); if (ret < 0) { gnutls_assert (); return ret; } break; #endif case GNUTLS_CRD_CERTIFICATE: ret = pack_certificate_auth_info (session, &sb); if (ret < 0) { gnutls_assert (); return ret; } break; default: return GNUTLS_E_INTERNAL_ERROR; } /* Auth_info structures copied. Now copy security_parameters_st. * packed_session must have allocated space for the security parameters. */ ret = pack_security_parameters (session, &sb); if (ret < 0) { gnutls_assert (); _gnutls_buffer_clear (&sb); return ret; } ret = _gnutls_ext_pack (session, &sb); if (ret < 0) { gnutls_assert (); _gnutls_buffer_clear (&sb); return ret; } ret = _gnutls_buffer_to_datum (&sb, packed_session); return ret; }
int print_info (gnutls_session_t session, int print_cert) { const char *tmp; gnutls_credentials_type_t cred; gnutls_kx_algorithm_t kx; unsigned char session_id[33]; size_t session_id_size = sizeof (session_id); /* print session ID */ gnutls_session_get_id (session, session_id, &session_id_size); printf ("- Session ID: %s\n", raw_to_string (session_id, session_id_size)); /* print the key exchange's algorithm name */ kx = gnutls_kx_get (session); cred = gnutls_auth_get_type (session); switch (cred) { #ifdef ENABLE_ANON case GNUTLS_CRD_ANON: if (kx == GNUTLS_KX_ANON_ECDH) print_ecdh_info (session, "Anonymous "); else print_dh_info (session, "Anonymous ", verbose); break; #endif #ifdef ENABLE_SRP case GNUTLS_CRD_SRP: /* This should be only called in server * side. */ if (gnutls_srp_server_get_username (session) != NULL) printf ("- SRP authentication. Connected as '%s'\n", gnutls_srp_server_get_username (session)); break; #endif #ifdef ENABLE_PSK case GNUTLS_CRD_PSK: /* This returns NULL in server side. */ if (gnutls_psk_client_get_hint (session) != NULL) printf ("- PSK authentication. PSK hint '%s'\n", gnutls_psk_client_get_hint (session)); /* This returns NULL in client side. */ if (gnutls_psk_server_get_username (session) != NULL) printf ("- PSK authentication. Connected as '%s'\n", gnutls_psk_server_get_username (session)); if (kx == GNUTLS_KX_DHE_PSK) print_dh_info (session, "Ephemeral ", verbose); if (kx == GNUTLS_KX_ECDHE_PSK) print_ecdh_info (session, "Ephemeral "); break; #endif case GNUTLS_CRD_IA: printf ("- TLS/IA authentication\n"); break; case GNUTLS_CRD_CERTIFICATE: { char dns[256]; size_t dns_size = sizeof (dns); unsigned int type; /* This fails in client side */ if (gnutls_server_name_get (session, dns, &dns_size, &type, 0) == 0) { printf ("- Given server name[%d]: %s\n", type, dns); } } print_cert_info (session, verbose?GNUTLS_CRT_PRINT_FULL:GNUTLS_CRT_PRINT_COMPACT, print_cert); if (kx == GNUTLS_KX_DHE_RSA || kx == GNUTLS_KX_DHE_DSS) print_dh_info (session, "Ephemeral ", verbose); else if (kx == GNUTLS_KX_ECDHE_RSA || kx == GNUTLS_KX_ECDHE_ECDSA) print_ecdh_info (session, "Ephemeral "); } tmp = SU (gnutls_protocol_get_name (gnutls_protocol_get_version (session))); printf ("- Version: %s\n", tmp); tmp = SU (gnutls_kx_get_name (kx)); printf ("- Key Exchange: %s\n", tmp); tmp = SU (gnutls_cipher_get_name (gnutls_cipher_get (session))); printf ("- Cipher: %s\n", tmp); tmp = SU (gnutls_mac_get_name (gnutls_mac_get (session))); printf ("- MAC: %s\n", tmp); tmp = SU (gnutls_compression_get_name (gnutls_compression_get (session))); printf ("- Compression: %s\n", tmp); if (verbose) { gnutls_datum_t cb; int rc; rc = gnutls_session_channel_binding (session, GNUTLS_CB_TLS_UNIQUE, &cb); if (rc) fprintf (stderr, "Channel binding error: %s\n", gnutls_strerror (rc)); else { size_t i; printf ("- Channel binding 'tls-unique': "); for (i = 0; i < cb.size; i++) printf ("%02x", cb.data[i]); printf ("\n"); } } /* Warning: Do not print anything more here. The 'Compression:' output MUST be the last non-verbose output. This is used by Emacs starttls.el code. */ fflush (stdout); return 0; }
static void tls_check_certificate(struct connection_state *scs, const char *remote_hostname) { int ret; unsigned int certstat; const gnutls_datum_t *cert_list; unsigned int cert_list_size = 0; gnutls_x509_crt_t cert; if (gnutls_auth_get_type(scs->tls_state) != GNUTLS_CRD_CERTIFICATE) { bad_certificate(scs, "Unable to get certificate from peer.\n"); return; /* bad_cert will exit if -skip-certificate-check was not given */ } ret = gnutls_certificate_verify_peers2(scs->tls_state, &certstat); if (ret < 0) { char errbuf[1024]; snprintf(errbuf, 1024, "could not verify certificate: %s (%d).\n", gnutls_strerror(ret), ret); bad_certificate(scs, (ret == GNUTLS_E_NO_CERTIFICATE_FOUND ? "server presented no certificate.\n" : errbuf)); return; #ifdef GNUTLS_CERT_CORRUPTED } else if (certstat & GNUTLS_CERT_CORRUPTED) { bad_certificate(scs, "server's certificate is corrupt.\n"); #endif } else if (certstat & GNUTLS_CERT_REVOKED) { bad_certificate(scs, "server's certificate has been revoked.\n"); } else if (certstat & GNUTLS_CERT_EXPIRED) { bad_certificate(scs, "server's certificate is expired.\n"); } else if (certstat & GNUTLS_CERT_INSECURE_ALGORITHM) { warn_certificate(scs, "server's certificate use an insecure algorithm.\n"); } else if (certstat & GNUTLS_CERT_INVALID) { if (gnutls_certificate_type_get(scs->tls_state) == GNUTLS_CRT_X509) { /* bad_certificate(scs, "server's certificate is not trusted.\n" "there may be a problem with the certificate stored in your certfile\n"); */ } else { bad_certificate(scs, "server's certificate is invalid or not X.509.\n" "there may be a problem with the certificate stored in your certfile\n"); } #if defined(GNUTLS_CERT_SIGNER_NOT_FOUND) } else if (certstat & GNUTLS_CERT_SIGNER_NOT_FOUND) { TDM(DEBUG_INFO, "server's certificate is not signed.\n"); TDM(DEBUG_INFO, "to verify that a certificate is trusted, use the certfile option.\n"); #endif #if defined(GNUTLS_CERT_NOT_TRUSTED) } else if (certstat & GNUTLS_CERT_NOT_TRUSTED) { TDM(DEBUG_INFO, "server's certificate is not trusted.\n"); TDM(DEBUG_INFO, "to verify that a certificate is trusted, use the certfile option.\n"); #endif } if (gnutls_x509_crt_init(&cert) < 0) { bad_certificate(scs, "Unable to initialize certificate data structure"); } /* not checking for not-yet-valid certs... this would make sense if we weren't just comparing to stored ones */ cert_list = gnutls_certificate_get_peers(scs->tls_state, &cert_list_size); if (gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER) < 0) { bad_certificate(scs, "Error processing certificate data"); } if (gnutls_x509_crt_get_expiration_time(cert) < time(NULL)) { bad_certificate(scs, "server's certificate has expired.\n"); } else if (gnutls_x509_crt_get_activation_time(cert) > time(NULL)) { bad_certificate(scs, "server's certificate is not yet valid.\n"); } else { TDM(DEBUG_INFO, "certificate passed time check.\n"); } if (gnutls_x509_crt_check_hostname(cert, remote_hostname) == 0) { char certificate_hostname[256]; size_t buflen = 255; gnutls_x509_crt_get_dn(cert, certificate_hostname, &buflen); /* gnutls_x509_extract_certificate_dn(&cert_list[0], &dn); */ TDM(DEBUG_INFO, "server's certificate (%s) does not match its hostname (%s).\n", certificate_hostname, remote_hostname); bad_certificate(scs, "server's certificate does not match its hostname.\n"); } else { if ((scs->pc)->debug >= DEBUG_INFO) { char certificate_hostname[256]; size_t buflen = 255; gnutls_x509_crt_get_dn(cert, certificate_hostname, &buflen); /* gnutls_x509_extract_certificate_dn(&cert_list[0], &dn); */ TDM(DEBUG_INFO, "server's certificate (%s) matched its hostname (%s).\n", certificate_hostname, remote_hostname); } } if (certificate_filename != NULL && tls_compare_certificates(&cert_list[0]) == 0) { bad_certificate(scs, "server's certificate was not found in the certificate file.\n"); } gnutls_x509_crt_deinit(cert); TDM(DEBUG_INFO, "certificate check ok.\n"); return; }