diff options
Diffstat (limited to 'src/gnutls_hooks.c')
| -rw-r--r-- | src/gnutls_hooks.c | 273 |
1 files changed, 211 insertions, 62 deletions
diff --git a/src/gnutls_hooks.c b/src/gnutls_hooks.c index 4364add..26917b8 100644 --- a/src/gnutls_hooks.c +++ b/src/gnutls_hooks.c | |||
| @@ -36,7 +36,10 @@ static int mpm_is_threaded; | |||
| 36 | 36 | ||
| 37 | static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt); | 37 | static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt); |
| 38 | /* use side==0 for server and side==1 for client */ | 38 | /* use side==0 for server and side==1 for client */ |
| 39 | static void mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt cert, | 39 | static void mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert, |
| 40 | int side, | ||
| 41 | int export_certificates_enabled); | ||
| 42 | static void mgs_add_common_pgpcert_vars(request_rec * r, gnutls_openpgp_crt_t cert, | ||
| 40 | int side, | 43 | int side, |
| 41 | int export_certificates_enabled); | 44 | int export_certificates_enabled); |
| 42 | 45 | ||
| @@ -68,9 +71,23 @@ int ret; | |||
| 68 | mpm_is_threaded = 0; | 71 | mpm_is_threaded = 0; |
| 69 | #endif | 72 | #endif |
| 70 | 73 | ||
| 74 | if (gnutls_check_version(LIBGNUTLS_VERSION)==NULL) { | ||
| 75 | fprintf(stderr, "gnutls_check_version() failed. Required: gnutls-%s Found: gnutls-%s\n", | ||
| 76 | LIBGNUTLS_VERSION, gnutls_check_version(NULL)); | ||
| 77 | return -3; | ||
| 78 | } | ||
| 79 | |||
| 71 | ret = gnutls_global_init(); | 80 | ret = gnutls_global_init(); |
| 72 | if (ret < 0) /* FIXME: can we print here? */ | 81 | if (ret < 0) { |
| 73 | exit(ret); | 82 | fprintf(stderr, "gnutls_global_init: %s\n", gnutls_strerror(ret)); |
| 83 | return -3; | ||
| 84 | } | ||
| 85 | |||
| 86 | ret = gnutls_global_init_extra(); | ||
| 87 | if (ret < 0) { | ||
| 88 | fprintf(stderr, "gnutls_global_init_extra: %s\n", gnutls_strerror(ret)); | ||
| 89 | return -3; | ||
| 90 | } | ||
| 74 | 91 | ||
| 75 | apr_pool_cleanup_register(pconf, NULL, mgs_cleanup_pre_config, | 92 | apr_pool_cleanup_register(pconf, NULL, mgs_cleanup_pre_config, |
| 76 | apr_pool_cleanup_null); | 93 | apr_pool_cleanup_null); |
| @@ -82,19 +99,18 @@ int ret; | |||
| 82 | 99 | ||
| 83 | gnutls_global_set_log_level(9); | 100 | gnutls_global_set_log_level(9); |
| 84 | gnutls_global_set_log_function(gnutls_debug_log_all); | 101 | gnutls_global_set_log_function(gnutls_debug_log_all); |
| 102 | apr_file_printf(debug_log_fp, "gnutls: %s\n", gnutls_check_version(NULL)); | ||
| 85 | #endif | 103 | #endif |
| 86 | 104 | ||
| 87 | return OK; | 105 | return OK; |
| 88 | } | 106 | } |
| 89 | 107 | ||
| 90 | /* We don't support openpgp certificates, yet */ | ||
| 91 | const static int cert_type_prio[2] = { GNUTLS_CRT_X509, 0 }; | ||
| 92 | |||
| 93 | static int mgs_select_virtual_server_cb(gnutls_session_t session) | 108 | static int mgs_select_virtual_server_cb(gnutls_session_t session) |
| 94 | { | 109 | { |
| 95 | mgs_handle_t *ctxt; | 110 | mgs_handle_t *ctxt; |
| 96 | mgs_srvconf_rec *tsc; | 111 | mgs_srvconf_rec *tsc; |
| 97 | int ret; | 112 | int ret; |
| 113 | int cprio[2]; | ||
| 98 | 114 | ||
| 99 | ctxt = gnutls_transport_get_ptr(session); | 115 | ctxt = gnutls_transport_get_ptr(session); |
| 100 | 116 | ||
| @@ -126,17 +142,22 @@ static int mgs_select_virtual_server_cb(gnutls_session_t session) | |||
| 126 | * negotiation. | 142 | * negotiation. |
| 127 | */ | 143 | */ |
| 128 | ret = gnutls_priority_set(session, ctxt->sc->priorities); | 144 | ret = gnutls_priority_set(session, ctxt->sc->priorities); |
| 129 | gnutls_certificate_type_set_priority(session, cert_type_prio); | ||
| 130 | |||
| 131 | |||
| 132 | /* actually it shouldn't fail since we have checked at startup */ | 145 | /* actually it shouldn't fail since we have checked at startup */ |
| 133 | if (ret < 0) | 146 | if (ret < 0) |
| 134 | return ret; | 147 | return ret; |
| 135 | 148 | ||
| 136 | /* allow separate caches per virtual host. Actually allowing the same is a | 149 | /* If both certificate types are not present disallow them from |
| 137 | * bad idea, since they might have different security requirements. | 150 | * being negotiated. |
| 138 | */ | 151 | */ |
| 139 | mgs_cache_session_init(ctxt); | 152 | if (ctxt->sc->certs_x509[0] != NULL && ctxt->sc->cert_pgp == NULL) { |
| 153 | cprio[0] = GNUTLS_CRT_X509; | ||
| 154 | cprio[1] = 0; | ||
| 155 | gnutls_certificate_type_set_priority( session, cprio); | ||
| 156 | } else if (ctxt->sc->cert_pgp != NULL && ctxt->sc->certs_x509[0]==NULL) { | ||
| 157 | cprio[0] = GNUTLS_CRT_OPENPGP; | ||
| 158 | cprio[1] = 0; | ||
| 159 | gnutls_certificate_type_set_priority( session, cprio); | ||
| 160 | } | ||
| 140 | 161 | ||
| 141 | return 0; | 162 | return 0; |
| 142 | } | 163 | } |
| @@ -147,15 +168,31 @@ static int cert_retrieve_fn(gnutls_session_t session, gnutls_retr_st * ret) | |||
| 147 | 168 | ||
| 148 | ctxt = gnutls_transport_get_ptr(session); | 169 | ctxt = gnutls_transport_get_ptr(session); |
| 149 | 170 | ||
| 150 | ret->type = GNUTLS_CRT_X509; | 171 | if (gnutls_certificate_type_get( session) == GNUTLS_CRT_X509) { |
| 151 | ret->ncerts = 1; | 172 | ret->type = GNUTLS_CRT_X509; |
| 152 | ret->deinit_all = 0; | 173 | ret->ncerts = ctxt->sc->certs_x509_num; |
| 174 | ret->deinit_all = 0; | ||
| 175 | |||
| 176 | ret->cert.x509 = ctxt->sc->certs_x509; | ||
| 177 | ret->key.x509 = ctxt->sc->privkey_x509; | ||
| 178 | |||
| 179 | return 0; | ||
| 180 | } else if (gnutls_certificate_type_get( session) == GNUTLS_CRT_OPENPGP) { | ||
| 181 | ret->type = GNUTLS_CRT_OPENPGP; | ||
| 182 | ret->ncerts = 1; | ||
| 183 | ret->deinit_all = 0; | ||
| 184 | |||
| 185 | ret->cert.pgp = ctxt->sc->cert_pgp; | ||
| 186 | ret->key.pgp = ctxt->sc->privkey_pgp; | ||
| 187 | |||
| 188 | return 0; | ||
| 189 | |||
| 190 | } | ||
| 153 | 191 | ||
| 154 | ret->cert.x509 = &ctxt->sc->cert_x509; | 192 | return GNUTLS_E_INTERNAL_ERROR; |
| 155 | ret->key.x509 = ctxt->sc->privkey_x509; | ||
| 156 | return 0; | ||
| 157 | } | 193 | } |
| 158 | 194 | ||
| 195 | /* 2048-bit group parameters from SRP specification */ | ||
| 159 | const char static_dh_params[] = "-----BEGIN DH PARAMETERS-----\n" | 196 | const char static_dh_params[] = "-----BEGIN DH PARAMETERS-----\n" |
| 160 | "MIIBBwKCAQCsa9tBMkqam/Fm3l4TiVgvr3K2ZRmH7gf8MZKUPbVgUKNzKcu0oJnt\n" | 197 | "MIIBBwKCAQCsa9tBMkqam/Fm3l4TiVgvr3K2ZRmH7gf8MZKUPbVgUKNzKcu0oJnt\n" |
| 161 | "gZPgdXdnoT3VIxKrSwMxDc1/SKnaBP1Q6Ag5ae23Z7DPYJUXmhY6s2YaBfvV+qro\n" | 198 | "gZPgdXdnoT3VIxKrSwMxDc1/SKnaBP1Q6Ag5ae23Z7DPYJUXmhY6s2YaBfvV+qro\n" |
| @@ -171,7 +208,7 @@ const char static_dh_params[] = "-----BEGIN DH PARAMETERS-----\n" | |||
| 171 | * Returns negative on error. | 208 | * Returns negative on error. |
| 172 | */ | 209 | */ |
| 173 | static int read_crt_cn(server_rec * s, apr_pool_t * p, | 210 | static int read_crt_cn(server_rec * s, apr_pool_t * p, |
| 174 | gnutls_x509_crt cert, char **cert_cn) | 211 | gnutls_x509_crt_t cert, char **cert_cn) |
| 175 | { | 212 | { |
| 176 | int rv = 0, i; | 213 | int rv = 0, i; |
| 177 | size_t data_len; | 214 | size_t data_len; |
| @@ -179,6 +216,7 @@ static int read_crt_cn(server_rec * s, apr_pool_t * p, | |||
| 179 | 216 | ||
| 180 | *cert_cn = NULL; | 217 | *cert_cn = NULL; |
| 181 | 218 | ||
| 219 | data_len = 0; | ||
| 182 | rv = gnutls_x509_crt_get_dn_by_oid(cert, | 220 | rv = gnutls_x509_crt_get_dn_by_oid(cert, |
| 183 | GNUTLS_OID_X520_COMMON_NAME, | 221 | GNUTLS_OID_X520_COMMON_NAME, |
| 184 | 0, 0, NULL, &data_len); | 222 | 0, 0, NULL, &data_len); |
| @@ -189,8 +227,8 @@ static int read_crt_cn(server_rec * s, apr_pool_t * p, | |||
| 189 | GNUTLS_OID_X520_COMMON_NAME, 0, | 227 | GNUTLS_OID_X520_COMMON_NAME, 0, |
| 190 | 0, *cert_cn, &data_len); | 228 | 0, *cert_cn, &data_len); |
| 191 | } else { /* No CN return subject alternative name */ | 229 | } else { /* No CN return subject alternative name */ |
| 192 | ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, | 230 | ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, |
| 193 | "No common name found in certificate for '%s:%d'. Looking for subject alternative name.", | 231 | "No common name found in certificate for '%s:%d'. Looking for subject alternative name...", |
| 194 | s->server_hostname, s->port); | 232 | s->server_hostname, s->port); |
| 195 | rv = 0; | 233 | rv = 0; |
| 196 | /* read subject alternative name */ | 234 | /* read subject alternative name */ |
| @@ -218,9 +256,33 @@ static int read_crt_cn(server_rec * s, apr_pool_t * p, | |||
| 218 | } | 256 | } |
| 219 | 257 | ||
| 220 | return rv; | 258 | return rv; |
| 259 | } | ||
| 260 | |||
| 261 | static int read_pgpcrt_cn(server_rec * s, apr_pool_t * p, | ||
| 262 | gnutls_openpgp_crt_t cert, char **cert_cn) | ||
| 263 | { | ||
| 264 | int rv = 0; | ||
| 265 | size_t data_len; | ||
| 266 | |||
| 267 | |||
| 268 | *cert_cn = NULL; | ||
| 269 | |||
| 270 | data_len = 0; | ||
| 271 | rv = gnutls_openpgp_crt_get_name(cert, 0, NULL, &data_len); | ||
| 272 | |||
| 273 | if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) { | ||
| 274 | *cert_cn = apr_palloc(p, data_len); | ||
| 275 | rv = gnutls_openpgp_crt_get_name(cert, 0, *cert_cn, &data_len); | ||
| 276 | } else { /* No CN return subject alternative name */ | ||
| 277 | ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, | ||
| 278 | "No name found in PGP certificate for '%s:%d'.", | ||
| 279 | s->server_hostname, s->port); | ||
| 280 | } | ||
| 221 | 281 | ||
| 282 | return rv; | ||
| 222 | } | 283 | } |
| 223 | 284 | ||
| 285 | |||
| 224 | int | 286 | int |
| 225 | mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog, | 287 | mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog, |
| 226 | apr_pool_t * ptemp, server_rec * base_server) | 288 | apr_pool_t * ptemp, server_rec * base_server) |
| @@ -334,7 +396,7 @@ mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog, | |||
| 334 | } | 396 | } |
| 335 | } | 397 | } |
| 336 | 398 | ||
| 337 | if (sc->cert_x509 == NULL | 399 | if (sc->certs_x509[0] == NULL |
| 338 | && sc->enabled == GNUTLS_ENABLED_TRUE) { | 400 | && sc->enabled == GNUTLS_ENABLED_TRUE) { |
| 339 | ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, | 401 | ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, |
| 340 | "[GnuTLS] - Host '%s:%d' is missing a " | 402 | "[GnuTLS] - Host '%s:%d' is missing a " |
| @@ -353,7 +415,10 @@ mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog, | |||
| 353 | } | 415 | } |
| 354 | 416 | ||
| 355 | if (sc->enabled == GNUTLS_ENABLED_TRUE) { | 417 | if (sc->enabled == GNUTLS_ENABLED_TRUE) { |
| 356 | rv = read_crt_cn(s, p, sc->cert_x509, &sc->cert_cn); | 418 | rv = read_crt_cn(s, p, sc->certs_x509[0], &sc->cert_cn); |
| 419 | if (rv < 0 && sc->cert_pgp != NULL) /* try openpgp certificate */ | ||
| 420 | rv = read_pgpcrt_cn(s, p, sc->cert_pgp, &sc->cert_cn); | ||
| 421 | |||
| 357 | if (rv < 0) { | 422 | if (rv < 0) { |
| 358 | ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, | 423 | ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, |
| 359 | "[GnuTLS] - Cannot find a certificate for host '%s:%d'!", | 424 | "[GnuTLS] - Cannot find a certificate for host '%s:%d'!", |
| @@ -482,15 +547,6 @@ mgs_srvconf_rec *mgs_find_sni_server(gnutls_session_t session) | |||
| 482 | 547 | ||
| 483 | ctxt = gnutls_transport_get_ptr(session); | 548 | ctxt = gnutls_transport_get_ptr(session); |
| 484 | 549 | ||
| 485 | sni_type = gnutls_certificate_type_get(session); | ||
| 486 | if (sni_type != GNUTLS_CRT_X509) { | ||
| 487 | /* In theory, we could support OpenPGP Certificates. Theory != code. */ | ||
| 488 | ap_log_error(APLOG_MARK, APLOG_CRIT, 0, | ||
| 489 | ctxt->c->base_server, | ||
| 490 | "GnuTLS: Only x509 Certificates are currently supported."); | ||
| 491 | return NULL; | ||
| 492 | } | ||
| 493 | |||
| 494 | rv = gnutls_server_name_get(ctxt->session, sni_name, | 550 | rv = gnutls_server_name_get(ctxt->session, sni_name, |
| 495 | &data_len, &sni_type, 0); | 551 | &data_len, &sni_type, 0); |
| 496 | 552 | ||
| @@ -591,6 +647,8 @@ static mgs_handle_t *create_gnutls_handle(apr_pool_t * pool, conn_rec * c) | |||
| 591 | gnutls_handshake_set_post_client_hello_function(ctxt->session, | 647 | gnutls_handshake_set_post_client_hello_function(ctxt->session, |
| 592 | mgs_select_virtual_server_cb); | 648 | mgs_select_virtual_server_cb); |
| 593 | 649 | ||
| 650 | mgs_cache_session_init(ctxt); | ||
| 651 | |||
| 594 | return ctxt; | 652 | return ctxt; |
| 595 | } | 653 | } |
| 596 | 654 | ||
| @@ -686,7 +744,11 @@ int mgs_hook_fixups(request_rec * r) | |||
| 686 | tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf)); | 744 | tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf)); |
| 687 | apr_table_setn(env, "SSL_SESSION_ID", apr_pstrdup(r->pool, tmp)); | 745 | apr_table_setn(env, "SSL_SESSION_ID", apr_pstrdup(r->pool, tmp)); |
| 688 | 746 | ||
| 689 | mgs_add_common_cert_vars(r, ctxt->sc->cert_x509, 0, | 747 | if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509) |
| 748 | mgs_add_common_cert_vars(r, ctxt->sc->certs_x509[0], 0, | ||
| 749 | ctxt->sc->export_certificates_enabled); | ||
| 750 | else if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_OPENPGP) | ||
| 751 | mgs_add_common_pgpcert_vars(r, ctxt->sc->cert_pgp, 0, | ||
| 690 | ctxt->sc->export_certificates_enabled); | 752 | ctxt->sc->export_certificates_enabled); |
| 691 | 753 | ||
| 692 | return rv; | 754 | return rv; |
| @@ -748,7 +810,7 @@ int mgs_hook_authz(request_rec * r) | |||
| 748 | */ | 810 | */ |
| 749 | #define MGS_SIDE ((side==0)?"SSL_SERVER":"SSL_CLIENT") | 811 | #define MGS_SIDE ((side==0)?"SSL_SERVER":"SSL_CLIENT") |
| 750 | static void | 812 | static void |
| 751 | mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt cert, int side, | 813 | mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert, int side, |
| 752 | int export_certificates_enabled) | 814 | int export_certificates_enabled) |
| 753 | { | 815 | { |
| 754 | unsigned char sbuf[64]; /* buffer to hold serials */ | 816 | unsigned char sbuf[64]; /* buffer to hold serials */ |
| @@ -795,7 +857,7 @@ mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt cert, int side, | |||
| 795 | apr_psprintf(r->pool, "%u", ret)); | 857 | apr_psprintf(r->pool, "%u", ret)); |
| 796 | 858 | ||
| 797 | apr_table_setn(env, | 859 | apr_table_setn(env, |
| 798 | apr_pstrcat(r->pool, MGS_SIDE, "_S_TYPE", NULL), "X.509"); | 860 | apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL), "X.509"); |
| 799 | 861 | ||
| 800 | tmp = | 862 | tmp = |
| 801 | mgs_time2sz(gnutls_x509_crt_get_expiration_time | 863 | mgs_time2sz(gnutls_x509_crt_get_expiration_time |
| @@ -837,34 +899,99 @@ mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt cert, int side, | |||
| 837 | 899 | ||
| 838 | if (ret == GNUTLS_SAN_DNSNAME) { | 900 | if (ret == GNUTLS_SAN_DNSNAME) { |
| 839 | apr_table_setn(env, | 901 | apr_table_setn(env, |
| 840 | apr_psprintf(r->pool, "%s_S_SAN%u", MGS_SIDE, i), | 902 | apr_psprintf(r->pool, "%s_S_AN%u", MGS_SIDE, i), |
| 841 | apr_psprintf(r->pool, "DNSNAME:%s", tmp2)); | 903 | apr_psprintf(r->pool, "DNSNAME:%s", tmp2)); |
| 842 | } else if (ret == GNUTLS_SAN_RFC822NAME) { | 904 | } else if (ret == GNUTLS_SAN_RFC822NAME) { |
| 843 | apr_table_setn(env, | 905 | apr_table_setn(env, |
| 844 | apr_psprintf(r->pool, "%s_S_SAN%u", MGS_SIDE, i), | 906 | apr_psprintf(r->pool, "%s_S_AN%u", MGS_SIDE, i), |
| 845 | apr_psprintf(r->pool, "RFC822NAME:%s", tmp2)); | 907 | apr_psprintf(r->pool, "RFC822NAME:%s", tmp2)); |
| 846 | } else if (ret == GNUTLS_SAN_URI) { | 908 | } else if (ret == GNUTLS_SAN_URI) { |
| 847 | apr_table_setn(env, | 909 | apr_table_setn(env, |
| 848 | apr_psprintf(r->pool, "%s_S_SAN%u", MGS_SIDE, i), | 910 | apr_psprintf(r->pool, "%s_S_AN%u", MGS_SIDE, i), |
| 849 | apr_psprintf(r->pool, "URI:%s", tmp2)); | 911 | apr_psprintf(r->pool, "URI:%s", tmp2)); |
| 850 | } else { | 912 | } else { |
| 851 | apr_table_setn(env, | 913 | apr_table_setn(env, |
| 852 | apr_psprintf(r->pool, "%s_S_SAN%u", MGS_SIDE, i), | 914 | apr_psprintf(r->pool, "%s_S_AN%u", MGS_SIDE, i), |
| 853 | "UNSUPPORTED"); | 915 | "UNSUPPORTED"); |
| 854 | } | 916 | } |
| 855 | } | 917 | } |
| 856 | } | 918 | } |
| 919 | } | ||
| 857 | 920 | ||
| 921 | static void | ||
| 922 | mgs_add_common_pgpcert_vars(request_rec * r, gnutls_openpgp_crt_t cert, int side, | ||
| 923 | int export_certificates_enabled) | ||
| 924 | { | ||
| 925 | unsigned char sbuf[64]; /* buffer to hold serials */ | ||
| 926 | char buf[AP_IOBUFSIZE]; | ||
| 927 | const char *tmp; | ||
| 928 | size_t len; | ||
| 929 | int ret; | ||
| 858 | 930 | ||
| 859 | } | 931 | apr_table_t *env = r->subprocess_env; |
| 860 | 932 | ||
| 933 | if (export_certificates_enabled != 0) { | ||
| 934 | char cert_buf[10 * 1024]; | ||
| 935 | len = sizeof(cert_buf); | ||
| 936 | |||
| 937 | if (gnutls_openpgp_crt_export | ||
| 938 | (cert, GNUTLS_OPENPGP_FMT_BASE64, cert_buf, &len) >= 0) | ||
| 939 | apr_table_setn(env, | ||
| 940 | apr_pstrcat(r->pool, MGS_SIDE, "_CERT", NULL), | ||
| 941 | apr_pstrmemdup(r->pool, cert_buf, len)); | ||
| 942 | |||
| 943 | } | ||
| 944 | |||
| 945 | len = sizeof(buf); | ||
| 946 | gnutls_openpgp_crt_get_name(cert, 0, buf, &len); | ||
| 947 | apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_NAME", NULL), | ||
| 948 | apr_pstrmemdup(r->pool, buf, len)); | ||
| 949 | |||
| 950 | len = sizeof(sbuf); | ||
| 951 | gnutls_openpgp_crt_get_fingerprint(cert, sbuf, &len); | ||
| 952 | tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf)); | ||
| 953 | apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_FINGERPRINT", NULL), | ||
| 954 | apr_pstrdup(r->pool, tmp)); | ||
| 955 | |||
| 956 | ret = gnutls_openpgp_crt_get_version(cert); | ||
| 957 | if (ret > 0) | ||
| 958 | apr_table_setn(env, | ||
| 959 | apr_pstrcat(r->pool, MGS_SIDE, "_M_VERSION", NULL), | ||
| 960 | apr_psprintf(r->pool, "%u", ret)); | ||
| 961 | |||
| 962 | apr_table_setn(env, | ||
| 963 | apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL), "OPENPGP"); | ||
| 964 | |||
| 965 | tmp = | ||
| 966 | mgs_time2sz(gnutls_openpgp_crt_get_expiration_time | ||
| 967 | (cert), buf, sizeof(buf)); | ||
| 968 | apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL), | ||
| 969 | apr_pstrdup(r->pool, tmp)); | ||
| 970 | |||
| 971 | tmp = | ||
| 972 | mgs_time2sz(gnutls_openpgp_crt_get_creation_time | ||
| 973 | (cert), buf, sizeof(buf)); | ||
| 974 | apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL), | ||
| 975 | apr_pstrdup(r->pool, tmp)); | ||
| 976 | |||
| 977 | ret = gnutls_openpgp_crt_get_pk_algorithm(cert, NULL); | ||
| 978 | if (ret >= 0) { | ||
| 979 | apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY", NULL), | ||
| 980 | gnutls_pk_algorithm_get_name(ret)); | ||
| 981 | } | ||
| 982 | |||
| 983 | } | ||
| 861 | 984 | ||
| 985 | /* TODO: Allow client sending a X.509 certificate chain */ | ||
| 862 | static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt) | 986 | static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt) |
| 863 | { | 987 | { |
| 864 | const gnutls_datum_t *cert_list; | 988 | const gnutls_datum_t *cert_list; |
| 865 | unsigned int cert_list_size, status, expired; | 989 | unsigned int cert_list_size, status, expired; |
| 866 | int rv, ret; | 990 | int rv, ret; |
| 867 | gnutls_x509_crt_t cert; | 991 | union { |
| 992 | gnutls_x509_crt_t x509; | ||
| 993 | gnutls_openpgp_crt_t pgp; | ||
| 994 | } cert; | ||
| 868 | apr_time_t activation_time, expiration_time, cur_time; | 995 | apr_time_t activation_time, expiration_time, cur_time; |
| 869 | 996 | ||
| 870 | cert_list = | 997 | cert_list = |
| @@ -890,32 +1017,56 @@ static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt) | |||
| 890 | return HTTP_FORBIDDEN; | 1017 | return HTTP_FORBIDDEN; |
| 891 | } | 1018 | } |
| 892 | 1019 | ||
| 893 | gnutls_x509_crt_init(&cert); | 1020 | if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509) { |
| 894 | rv = gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER); | 1021 | gnutls_x509_crt_init(&cert.x509); |
| 1022 | rv = gnutls_x509_crt_import(cert.x509, &cert_list[0], GNUTLS_X509_FMT_DER); | ||
| 1023 | } else if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_OPENPGP) { | ||
| 1024 | gnutls_openpgp_crt_init(&cert.pgp); | ||
| 1025 | rv = gnutls_openpgp_crt_import(cert.pgp, &cert_list[0], GNUTLS_OPENPGP_FMT_RAW); | ||
| 1026 | } else return HTTP_FORBIDDEN; | ||
| 1027 | |||
| 895 | if (rv < 0) { | 1028 | if (rv < 0) { |
| 896 | ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, | 1029 | ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, |
| 897 | "GnuTLS: Failed to Verify Peer: " | 1030 | "GnuTLS: Failed to Verify Peer: " |
| 898 | "Failed to import peer certificates."); | 1031 | "Failed to import peer certificates."); |
| 899 | ret = HTTP_FORBIDDEN; | 1032 | ret = HTTP_FORBIDDEN; |
| 900 | goto exit; | 1033 | goto exit; |
| 901 | } | 1034 | } |
| 902 | 1035 | ||
| 903 | apr_time_ansi_put(&expiration_time, | 1036 | if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509) { |
| 904 | gnutls_x509_crt_get_expiration_time(cert)); | 1037 | apr_time_ansi_put(&expiration_time, |
| 905 | apr_time_ansi_put(&activation_time, | 1038 | gnutls_x509_crt_get_expiration_time(cert.x509)); |
| 906 | gnutls_x509_crt_get_activation_time(cert)); | 1039 | apr_time_ansi_put(&activation_time, |
| 1040 | gnutls_x509_crt_get_activation_time(cert.x509)); | ||
| 907 | 1041 | ||
| 908 | rv = gnutls_x509_crt_verify(cert, ctxt->sc->ca_list, | 1042 | rv = gnutls_x509_crt_verify(cert.x509, ctxt->sc->ca_list, |
| 909 | ctxt->sc->ca_list_size, 0, &status); | 1043 | ctxt->sc->ca_list_size, 0, &status); |
| 1044 | } else { | ||
| 1045 | apr_time_ansi_put(&expiration_time, | ||
| 1046 | gnutls_openpgp_crt_get_expiration_time(cert.pgp)); | ||
| 1047 | apr_time_ansi_put(&activation_time, | ||
| 1048 | gnutls_openpgp_crt_get_creation_time(cert.pgp)); | ||
| 1049 | |||
| 1050 | rv = gnutls_openpgp_crt_verify_ring(cert.pgp, ctxt->sc->pgp_list, | ||
| 1051 | 0, &status); | ||
| 1052 | } | ||
| 910 | 1053 | ||
| 911 | if (rv < 0) { | 1054 | if (rv < 0) { |
| 912 | ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, | 1055 | ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, |
| 913 | "GnuTLS: Failed to Verify Peer certificate: (%d) %s", | 1056 | "GnuTLS: Failed to Verify Peer certificate: (%d) %s", |
| 914 | rv, gnutls_strerror(rv)); | 1057 | rv, gnutls_strerror(rv)); |
| 1058 | if (rv == GNUTLS_E_NO_CERTIFICATE_FOUND) | ||
| 1059 | ap_log_rerror(APLOG_MARK, APLOG_EMERG, 0, r, | ||
| 1060 | "GnuTLS: No certificate was found for verification. Did you set the GnuTLSX509CAFile or GnuTLSPGPKeyringFile directives?"); | ||
| 915 | ret = HTTP_FORBIDDEN; | 1061 | ret = HTTP_FORBIDDEN; |
| 916 | goto exit; | 1062 | goto exit; |
| 917 | } | 1063 | } |
| 918 | 1064 | ||
| 1065 | /* TODO: X509 CRL Verification. */ | ||
| 1066 | /* May add later if anyone needs it. | ||
| 1067 | */ | ||
| 1068 | /* ret = gnutls_x509_crt_check_revocation(crt, crl_list, crl_list_size); */ | ||
| 1069 | |||
| 919 | expired = 0; | 1070 | expired = 0; |
| 920 | cur_time = apr_time_now(); | 1071 | cur_time = apr_time_now(); |
| 921 | if (activation_time > cur_time) { | 1072 | if (activation_time > cur_time) { |
| @@ -950,16 +1101,11 @@ static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt) | |||
| 950 | "GnuTLS: Peer Certificate is revoked."); | 1101 | "GnuTLS: Peer Certificate is revoked."); |
| 951 | } | 1102 | } |
| 952 | 1103 | ||
| 953 | /* TODO: Further Verification. */ | 1104 | if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509) |
| 954 | /* Revocation is X.509 non workable paradigm, I really doubt implementation | 1105 | mgs_add_common_cert_vars(r, cert.x509, 1, |
| 955 | * is worth doing --nmav | 1106 | ctxt->sc->export_certificates_enabled); |
| 956 | */ | 1107 | else if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_OPENPGP) |
| 957 | /// ret = gnutls_x509_crt_check_revocation(crt, crl_list, crl_list_size); | 1108 | mgs_add_common_pgpcert_vars(r, cert.pgp, 1, |
| 958 | |||
| 959 | // mgs_hook_fixups(r); | ||
| 960 | // rv = mgs_authz_lua(r); | ||
| 961 | |||
| 962 | mgs_add_common_cert_vars(r, cert, 1, | ||
| 963 | ctxt->sc->export_certificates_enabled); | 1109 | ctxt->sc->export_certificates_enabled); |
| 964 | 1110 | ||
| 965 | { | 1111 | { |
| @@ -983,7 +1129,10 @@ static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt) | |||
| 983 | } | 1129 | } |
| 984 | 1130 | ||
| 985 | exit: | 1131 | exit: |
| 986 | gnutls_x509_crt_deinit(cert); | 1132 | if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509) |
| 1133 | gnutls_x509_crt_deinit(cert.x509); | ||
| 1134 | else if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_OPENPGP) | ||
| 1135 | gnutls_openpgp_crt_deinit(cert.pgp); | ||
| 987 | return ret; | 1136 | return ret; |
| 988 | 1137 | ||
| 989 | 1138 | ||
