diff options
| -rw-r--r-- | NEWS | 5 | ||||
| -rw-r--r-- | include/mod_gnutls.h.in | 14 | ||||
| -rw-r--r-- | src/gnutls_config.c | 111 | ||||
| -rw-r--r-- | src/gnutls_hooks.c | 220 | ||||
| -rw-r--r-- | src/mod_gnutls.c | 16 |
5 files changed, 326 insertions, 40 deletions
| @@ -1,3 +1,7 @@ | |||
| 1 | ** Version 0.5.0 | ||
| 2 | |||
| 3 | - Added support for OpenPGP keys. | ||
| 4 | |||
| 1 | ** Version 0.4.2 (2007-12-10) | 5 | ** Version 0.4.2 (2007-12-10) |
| 2 | 6 | ||
| 3 | - Added support for sending a certificate chain. | 7 | - Added support for sending a certificate chain. |
| @@ -23,3 +27,4 @@ to David Hrbáč. | |||
| 23 | - Better handling of GnuTLSDHFile and GnuTLSRSAFile. | 27 | - Better handling of GnuTLSDHFile and GnuTLSRSAFile. |
| 24 | 28 | ||
| 25 | - No longer default paths for RSA and DH parameter files. | 29 | - No longer default paths for RSA and DH parameter files. |
| 30 | [5~ \ No newline at end of file | ||
diff --git a/include/mod_gnutls.h.in b/include/mod_gnutls.h.in index a0f6581..db7e7dd 100644 --- a/include/mod_gnutls.h.in +++ b/include/mod_gnutls.h.in | |||
| @@ -29,6 +29,8 @@ | |||
| 29 | 29 | ||
| 30 | #include <gcrypt.h> | 30 | #include <gcrypt.h> |
| 31 | #include <gnutls/gnutls.h> | 31 | #include <gnutls/gnutls.h> |
| 32 | #include <gnutls/extra.h> | ||
| 33 | #include <gnutls/openpgp.h> | ||
| 32 | #include <gnutls/x509.h> | 34 | #include <gnutls/x509.h> |
| 33 | 35 | ||
| 34 | #ifndef __mod_gnutls_h_inc | 36 | #ifndef __mod_gnutls_h_inc |
| @@ -94,6 +96,8 @@ typedef struct | |||
| 94 | gnutls_x509_crt_t certs_x509[MAX_CHAIN_SIZE]; /* A certificate chain */ | 96 | gnutls_x509_crt_t certs_x509[MAX_CHAIN_SIZE]; /* A certificate chain */ |
| 95 | unsigned int certs_x509_num; | 97 | unsigned int certs_x509_num; |
| 96 | gnutls_x509_privkey_t privkey_x509; | 98 | gnutls_x509_privkey_t privkey_x509; |
| 99 | gnutls_openpgp_crt_t cert_pgp; /* A certificate chain */ | ||
| 100 | gnutls_openpgp_privkey_t privkey_pgp; | ||
| 97 | int enabled; | 101 | int enabled; |
| 98 | /* whether to send the PEM encoded certificates | 102 | /* whether to send the PEM encoded certificates |
| 99 | * to CGIs | 103 | * to CGIs |
| @@ -108,6 +112,7 @@ typedef struct | |||
| 108 | const char* srp_tpasswd_file; | 112 | const char* srp_tpasswd_file; |
| 109 | const char* srp_tpasswd_conf_file; | 113 | const char* srp_tpasswd_conf_file; |
| 110 | gnutls_x509_crt_t ca_list[MAX_CA_CRTS]; | 114 | gnutls_x509_crt_t ca_list[MAX_CA_CRTS]; |
| 115 | gnutls_openpgp_keyring_t pgp_list; | ||
| 111 | unsigned int ca_list_size; | 116 | unsigned int ca_list_size; |
| 112 | int client_verify_mode; | 117 | int client_verify_mode; |
| 113 | } mgs_srvconf_rec; | 118 | } mgs_srvconf_rec; |
| @@ -254,6 +259,12 @@ const char *mgs_set_cert_file(cmd_parms * parms, void *dummy, | |||
| 254 | const char *mgs_set_key_file(cmd_parms * parms, void *dummy, | 259 | const char *mgs_set_key_file(cmd_parms * parms, void *dummy, |
| 255 | const char *arg); | 260 | const char *arg); |
| 256 | 261 | ||
| 262 | const char *mgs_set_pgpcert_file(cmd_parms * parms, void *dummy, | ||
| 263 | const char *arg); | ||
| 264 | |||
| 265 | const char *mgs_set_pgpkey_file(cmd_parms * parms, void *dummy, | ||
| 266 | const char *arg); | ||
| 267 | |||
| 257 | const char *mgs_set_cache(cmd_parms * parms, void *dummy, | 268 | const char *mgs_set_cache(cmd_parms * parms, void *dummy, |
| 258 | const char *type, const char* arg); | 269 | const char *type, const char* arg); |
| 259 | 270 | ||
| @@ -266,6 +277,9 @@ const char *mgs_set_client_verify(cmd_parms * parms, void *dummy, | |||
| 266 | const char *mgs_set_client_ca_file(cmd_parms * parms, void *dummy, | 277 | const char *mgs_set_client_ca_file(cmd_parms * parms, void *dummy, |
| 267 | const char *arg); | 278 | const char *arg); |
| 268 | 279 | ||
| 280 | const char *mgs_set_keyring_file(cmd_parms * parms, void *dummy, | ||
| 281 | const char *arg); | ||
| 282 | |||
| 269 | const char *mgs_set_enabled(cmd_parms * parms, void *dummy, | 283 | const char *mgs_set_enabled(cmd_parms * parms, void *dummy, |
| 270 | const char *arg); | 284 | const char *arg); |
| 271 | const char *mgs_set_export_certificates_enabled(cmd_parms * parms, void *dummy, | 285 | const char *mgs_set_export_certificates_enabled(cmd_parms * parms, void *dummy, |
diff --git a/src/gnutls_config.c b/src/gnutls_config.c index 8d6308a..4dccd08 100644 --- a/src/gnutls_config.c +++ b/src/gnutls_config.c | |||
| @@ -202,6 +202,85 @@ const char *mgs_set_key_file(cmd_parms * parms, void *dummy, | |||
| 202 | return NULL; | 202 | return NULL; |
| 203 | } | 203 | } |
| 204 | 204 | ||
| 205 | const char *mgs_set_pgpcert_file(cmd_parms * parms, void *dummy, | ||
| 206 | const char *arg) | ||
| 207 | { | ||
| 208 | int ret; | ||
| 209 | gnutls_datum_t data; | ||
| 210 | const char *file; | ||
| 211 | apr_pool_t *spool; | ||
| 212 | mgs_srvconf_rec *sc = | ||
| 213 | (mgs_srvconf_rec *) ap_get_module_config(parms->server-> | ||
| 214 | module_config, | ||
| 215 | &gnutls_module); | ||
| 216 | apr_pool_create(&spool, parms->pool); | ||
| 217 | |||
| 218 | file = ap_server_root_relative(spool, arg); | ||
| 219 | |||
| 220 | if (load_datum_from_file(spool, file, &data) != 0) { | ||
| 221 | return apr_psprintf(parms->pool, "GnuTLS: Error Reading " | ||
| 222 | "Certificate '%s'", file); | ||
| 223 | } | ||
| 224 | |||
| 225 | ret = gnutls_openpgp_crt_init( &sc->cert_pgp); | ||
| 226 | if (ret < 0) { | ||
| 227 | return apr_psprintf(parms->pool, "GnuTLS: Failed to Init " | ||
| 228 | "PGP Certificate: (%d) %s", ret, | ||
| 229 | gnutls_strerror(ret)); | ||
| 230 | } | ||
| 231 | |||
| 232 | |||
| 233 | ret = | ||
| 234 | gnutls_openpgp_crt_import(sc->cert_pgp, &data, GNUTLS_OPENPGP_FMT_BASE64); | ||
| 235 | if (ret < 0) { | ||
| 236 | return apr_psprintf(parms->pool, "GnuTLS: Failed to Import " | ||
| 237 | "PGP Certificate '%s': (%d) %s", file, ret, | ||
| 238 | gnutls_strerror(ret)); | ||
| 239 | } | ||
| 240 | |||
| 241 | apr_pool_destroy(spool); | ||
| 242 | return NULL; | ||
| 243 | } | ||
| 244 | |||
| 245 | const char *mgs_set_pgpkey_file(cmd_parms * parms, void *dummy, | ||
| 246 | const char *arg) | ||
| 247 | { | ||
| 248 | int ret; | ||
| 249 | gnutls_datum_t data; | ||
| 250 | const char *file; | ||
| 251 | apr_pool_t *spool; | ||
| 252 | mgs_srvconf_rec *sc = | ||
| 253 | (mgs_srvconf_rec *) ap_get_module_config(parms->server-> | ||
| 254 | module_config, | ||
| 255 | &gnutls_module); | ||
| 256 | apr_pool_create(&spool, parms->pool); | ||
| 257 | |||
| 258 | file = ap_server_root_relative(spool, arg); | ||
| 259 | |||
| 260 | if (load_datum_from_file(spool, file, &data) != 0) { | ||
| 261 | return apr_psprintf(parms->pool, "GnuTLS: Error Reading " | ||
| 262 | "Private Key '%s'", file); | ||
| 263 | } | ||
| 264 | |||
| 265 | ret = gnutls_openpgp_privkey_init(&sc->privkey_pgp); | ||
| 266 | if (ret < 0) { | ||
| 267 | return apr_psprintf(parms->pool, "GnuTLS: Failed to initialize" | ||
| 268 | ": (%d) %s", ret, gnutls_strerror(ret)); | ||
| 269 | } | ||
| 270 | |||
| 271 | ret = | ||
| 272 | gnutls_openpgp_privkey_import(sc->privkey_pgp, &data, | ||
| 273 | GNUTLS_OPENPGP_FMT_BASE64, NULL, 0); | ||
| 274 | if (ret != 0) { | ||
| 275 | return apr_psprintf(parms->pool, "GnuTLS: Failed to Import " | ||
| 276 | "PGP Private Key '%s': (%d) %s", file, ret, | ||
| 277 | gnutls_strerror(ret)); | ||
| 278 | } | ||
| 279 | apr_pool_destroy(spool); | ||
| 280 | return NULL; | ||
| 281 | } | ||
| 282 | |||
| 283 | |||
| 205 | const char *mgs_set_srp_tpasswd_file(cmd_parms * parms, void *dummy, | 284 | const char *mgs_set_srp_tpasswd_file(cmd_parms * parms, void *dummy, |
| 206 | const char *arg) | 285 | const char *arg) |
| 207 | { | 286 | { |
| @@ -350,6 +429,38 @@ const char *mgs_set_client_ca_file(cmd_parms * parms, void *dummy, | |||
| 350 | return NULL; | 429 | return NULL; |
| 351 | } | 430 | } |
| 352 | 431 | ||
| 432 | const char *mgs_set_keyring_file(cmd_parms * parms, void *dummy, | ||
| 433 | const char *arg) | ||
| 434 | { | ||
| 435 | int rv; | ||
| 436 | const char *file; | ||
| 437 | apr_pool_t *spool; | ||
| 438 | gnutls_datum_t data; | ||
| 439 | |||
| 440 | mgs_srvconf_rec *sc = | ||
| 441 | (mgs_srvconf_rec *) ap_get_module_config(parms->server-> | ||
| 442 | module_config, | ||
| 443 | &gnutls_module); | ||
| 444 | apr_pool_create(&spool, parms->pool); | ||
| 445 | |||
| 446 | file = ap_server_root_relative(spool, arg); | ||
| 447 | |||
| 448 | if (load_datum_from_file(spool, file, &data) != 0) { | ||
| 449 | return apr_psprintf(parms->pool, "GnuTLS: Error Reading " | ||
| 450 | "Keyring File '%s'", file); | ||
| 451 | } | ||
| 452 | |||
| 453 | rv = gnutls_openpgp_keyring_import(sc->pgp_list, &data, GNUTLS_OPENPGP_FMT_BASE64); | ||
| 454 | if (rv < 0) { | ||
| 455 | return apr_psprintf(parms->pool, "GnuTLS: Failed to load " | ||
| 456 | "Keyring File '%s': (%d) %s", file, rv, | ||
| 457 | gnutls_strerror(rv)); | ||
| 458 | } | ||
| 459 | |||
| 460 | apr_pool_destroy(spool); | ||
| 461 | return NULL; | ||
| 462 | } | ||
| 463 | |||
| 353 | const char *mgs_set_enabled(cmd_parms * parms, void *dummy, | 464 | const char *mgs_set_enabled(cmd_parms * parms, void *dummy, |
| 354 | const char *arg) | 465 | const char *arg) |
| 355 | { | 466 | { |
diff --git a/src/gnutls_hooks.c b/src/gnutls_hooks.c index 55a1120..39fcd2b 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 | ||
| @@ -71,6 +74,10 @@ int ret; | |||
| 71 | ret = gnutls_global_init(); | 74 | ret = gnutls_global_init(); |
| 72 | if (ret < 0) /* FIXME: can we print here? */ | 75 | if (ret < 0) /* FIXME: can we print here? */ |
| 73 | exit(ret); | 76 | exit(ret); |
| 77 | |||
| 78 | ret = gnutls_global_init_extra(); | ||
| 79 | if (ret < 0) /* FIXME: can we print here? */ | ||
| 80 | exit(ret); | ||
| 74 | 81 | ||
| 75 | apr_pool_cleanup_register(pconf, NULL, mgs_cleanup_pre_config, | 82 | apr_pool_cleanup_register(pconf, NULL, mgs_cleanup_pre_config, |
| 76 | apr_pool_cleanup_null); | 83 | apr_pool_cleanup_null); |
| @@ -87,14 +94,12 @@ int ret; | |||
| 87 | return OK; | 94 | return OK; |
| 88 | } | 95 | } |
| 89 | 96 | ||
| 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) | 97 | static int mgs_select_virtual_server_cb(gnutls_session_t session) |
| 94 | { | 98 | { |
| 95 | mgs_handle_t *ctxt; | 99 | mgs_handle_t *ctxt; |
| 96 | mgs_srvconf_rec *tsc; | 100 | mgs_srvconf_rec *tsc; |
| 97 | int ret; | 101 | int ret; |
| 102 | int cprio[3] = { GNUTLS_CRT_X509, GNUTLS_CRT_OPENPGP, 0 }; | ||
| 98 | 103 | ||
| 99 | ctxt = gnutls_transport_get_ptr(session); | 104 | ctxt = gnutls_transport_get_ptr(session); |
| 100 | 105 | ||
| @@ -126,8 +131,20 @@ static int mgs_select_virtual_server_cb(gnutls_session_t session) | |||
| 126 | * negotiation. | 131 | * negotiation. |
| 127 | */ | 132 | */ |
| 128 | ret = gnutls_priority_set(session, ctxt->sc->priorities); | 133 | ret = gnutls_priority_set(session, ctxt->sc->priorities); |
| 129 | gnutls_certificate_type_set_priority(session, cert_type_prio); | ||
| 130 | 134 | ||
| 135 | /* Do not allow the user to override certificate priorities. We know | ||
| 136 | * better if the certificate of certain type is enabled. */ | ||
| 137 | if (ctxt->sc->cert_pgp != NULL && ctxt->sc->certs_x509[0] != NULL) { | ||
| 138 | gnutls_certificate_type_set_priority( session, cprio); | ||
| 139 | } else if (ctxt->sc->certs_x509[0] != NULL) { | ||
| 140 | cprio[0] = GNUTLS_CRT_X509; | ||
| 141 | cprio[1] = 0; | ||
| 142 | gnutls_certificate_type_set_priority( session, cprio); | ||
| 143 | } else if (ctxt->sc->cert_pgp != NULL) { | ||
| 144 | cprio[0] = GNUTLS_CRT_OPENPGP; | ||
| 145 | cprio[1] = 0; | ||
| 146 | gnutls_certificate_type_set_priority( session, cprio); | ||
| 147 | } | ||
| 131 | 148 | ||
| 132 | /* actually it shouldn't fail since we have checked at startup */ | 149 | /* actually it shouldn't fail since we have checked at startup */ |
| 133 | if (ret < 0) | 150 | if (ret < 0) |
| @@ -143,13 +160,28 @@ static int cert_retrieve_fn(gnutls_session_t session, gnutls_retr_st * ret) | |||
| 143 | 160 | ||
| 144 | ctxt = gnutls_transport_get_ptr(session); | 161 | ctxt = gnutls_transport_get_ptr(session); |
| 145 | 162 | ||
| 146 | ret->type = GNUTLS_CRT_X509; | 163 | if (gnutls_certificate_type_get( session) == GNUTLS_CRT_X509) { |
| 147 | ret->ncerts = ctxt->sc->certs_x509_num; | 164 | ret->type = GNUTLS_CRT_X509; |
| 148 | ret->deinit_all = 0; | 165 | ret->ncerts = ctxt->sc->certs_x509_num; |
| 166 | ret->deinit_all = 0; | ||
| 167 | |||
| 168 | ret->cert.x509 = ctxt->sc->certs_x509; | ||
| 169 | ret->key.x509 = ctxt->sc->privkey_x509; | ||
| 170 | |||
| 171 | return 0; | ||
| 172 | } else if (gnutls_certificate_type_get( session) == GNUTLS_CRT_OPENPGP) { | ||
| 173 | ret->type = GNUTLS_CRT_OPENPGP; | ||
| 174 | ret->ncerts = 1; | ||
| 175 | ret->deinit_all = 0; | ||
| 176 | |||
| 177 | ret->cert.pgp = ctxt->sc->cert_pgp; | ||
| 178 | ret->key.pgp = ctxt->sc->privkey_pgp; | ||
| 179 | |||
| 180 | return 0; | ||
| 181 | |||
| 182 | } | ||
| 149 | 183 | ||
| 150 | ret->cert.x509 = ctxt->sc->certs_x509; | 184 | return GNUTLS_E_INTERNAL_ERROR; |
| 151 | ret->key.x509 = ctxt->sc->privkey_x509; | ||
| 152 | return 0; | ||
| 153 | } | 185 | } |
| 154 | 186 | ||
| 155 | const char static_dh_params[] = "-----BEGIN DH PARAMETERS-----\n" | 187 | const char static_dh_params[] = "-----BEGIN DH PARAMETERS-----\n" |
| @@ -167,7 +199,7 @@ const char static_dh_params[] = "-----BEGIN DH PARAMETERS-----\n" | |||
| 167 | * Returns negative on error. | 199 | * Returns negative on error. |
| 168 | */ | 200 | */ |
| 169 | static int read_crt_cn(server_rec * s, apr_pool_t * p, | 201 | static int read_crt_cn(server_rec * s, apr_pool_t * p, |
| 170 | gnutls_x509_crt cert, char **cert_cn) | 202 | gnutls_x509_crt_t cert, char **cert_cn) |
| 171 | { | 203 | { |
| 172 | int rv = 0, i; | 204 | int rv = 0, i; |
| 173 | size_t data_len; | 205 | size_t data_len; |
| @@ -175,6 +207,7 @@ static int read_crt_cn(server_rec * s, apr_pool_t * p, | |||
| 175 | 207 | ||
| 176 | *cert_cn = NULL; | 208 | *cert_cn = NULL; |
| 177 | 209 | ||
| 210 | data_len = 0; | ||
| 178 | rv = gnutls_x509_crt_get_dn_by_oid(cert, | 211 | rv = gnutls_x509_crt_get_dn_by_oid(cert, |
| 179 | GNUTLS_OID_X520_COMMON_NAME, | 212 | GNUTLS_OID_X520_COMMON_NAME, |
| 180 | 0, 0, NULL, &data_len); | 213 | 0, 0, NULL, &data_len); |
| @@ -186,7 +219,7 @@ static int read_crt_cn(server_rec * s, apr_pool_t * p, | |||
| 186 | 0, *cert_cn, &data_len); | 219 | 0, *cert_cn, &data_len); |
| 187 | } else { /* No CN return subject alternative name */ | 220 | } else { /* No CN return subject alternative name */ |
| 188 | ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, | 221 | ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, |
| 189 | "No common name found in certificate for '%s:%d'. Looking for subject alternative name.", | 222 | "No common name found in certificate for '%s:%d'. Looking for subject alternative name...", |
| 190 | s->server_hostname, s->port); | 223 | s->server_hostname, s->port); |
| 191 | rv = 0; | 224 | rv = 0; |
| 192 | /* read subject alternative name */ | 225 | /* read subject alternative name */ |
| @@ -214,9 +247,33 @@ static int read_crt_cn(server_rec * s, apr_pool_t * p, | |||
| 214 | } | 247 | } |
| 215 | 248 | ||
| 216 | return rv; | 249 | return rv; |
| 250 | } | ||
| 251 | |||
| 252 | static int read_pgpcrt_cn(server_rec * s, apr_pool_t * p, | ||
| 253 | gnutls_openpgp_crt_t cert, char **cert_cn) | ||
| 254 | { | ||
| 255 | int rv = 0; | ||
| 256 | size_t data_len; | ||
| 257 | |||
| 258 | |||
| 259 | *cert_cn = NULL; | ||
| 260 | |||
| 261 | data_len = 0; | ||
| 262 | rv = gnutls_openpgp_crt_get_name(cert, 0, NULL, &data_len); | ||
| 263 | |||
| 264 | if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) { | ||
| 265 | *cert_cn = apr_palloc(p, data_len); | ||
| 266 | rv = gnutls_openpgp_crt_get_name(cert, 0, *cert_cn, &data_len); | ||
| 267 | } else { /* No CN return subject alternative name */ | ||
| 268 | ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, | ||
| 269 | "No name found in PGP certificate for '%s:%d'.", | ||
| 270 | s->server_hostname, s->port); | ||
| 271 | } | ||
| 217 | 272 | ||
| 273 | return rv; | ||
| 218 | } | 274 | } |
| 219 | 275 | ||
| 276 | |||
| 220 | int | 277 | int |
| 221 | mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog, | 278 | mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog, |
| 222 | apr_pool_t * ptemp, server_rec * base_server) | 279 | apr_pool_t * ptemp, server_rec * base_server) |
| @@ -350,6 +407,9 @@ mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog, | |||
| 350 | 407 | ||
| 351 | if (sc->enabled == GNUTLS_ENABLED_TRUE) { | 408 | if (sc->enabled == GNUTLS_ENABLED_TRUE) { |
| 352 | rv = read_crt_cn(s, p, sc->certs_x509[0], &sc->cert_cn); | 409 | rv = read_crt_cn(s, p, sc->certs_x509[0], &sc->cert_cn); |
| 410 | if (rv < 0) /* try openpgp certificate */ | ||
| 411 | rv = read_pgpcrt_cn(s, p, sc->cert_pgp, &sc->cert_cn); | ||
| 412 | |||
| 353 | if (rv < 0) { | 413 | if (rv < 0) { |
| 354 | ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, | 414 | ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, |
| 355 | "[GnuTLS] - Cannot find a certificate for host '%s:%d'!", | 415 | "[GnuTLS] - Cannot find a certificate for host '%s:%d'!", |
| @@ -478,15 +538,6 @@ mgs_srvconf_rec *mgs_find_sni_server(gnutls_session_t session) | |||
| 478 | 538 | ||
| 479 | ctxt = gnutls_transport_get_ptr(session); | 539 | ctxt = gnutls_transport_get_ptr(session); |
| 480 | 540 | ||
| 481 | sni_type = gnutls_certificate_type_get(session); | ||
| 482 | if (sni_type != GNUTLS_CRT_X509) { | ||
| 483 | /* In theory, we could support OpenPGP Certificates. Theory != code. */ | ||
| 484 | ap_log_error(APLOG_MARK, APLOG_CRIT, 0, | ||
| 485 | ctxt->c->base_server, | ||
| 486 | "GnuTLS: Only x509 Certificates are currently supported."); | ||
| 487 | return NULL; | ||
| 488 | } | ||
| 489 | |||
| 490 | rv = gnutls_server_name_get(ctxt->session, sni_name, | 541 | rv = gnutls_server_name_get(ctxt->session, sni_name, |
| 491 | &data_len, &sni_type, 0); | 542 | &data_len, &sni_type, 0); |
| 492 | 543 | ||
| @@ -684,7 +735,11 @@ int mgs_hook_fixups(request_rec * r) | |||
| 684 | tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf)); | 735 | tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf)); |
| 685 | apr_table_setn(env, "SSL_SESSION_ID", apr_pstrdup(r->pool, tmp)); | 736 | apr_table_setn(env, "SSL_SESSION_ID", apr_pstrdup(r->pool, tmp)); |
| 686 | 737 | ||
| 687 | mgs_add_common_cert_vars(r, ctxt->sc->certs_x509[0], 0, | 738 | if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509) |
| 739 | mgs_add_common_cert_vars(r, ctxt->sc->certs_x509[0], 0, | ||
| 740 | ctxt->sc->export_certificates_enabled); | ||
| 741 | else if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_OPENPGP) | ||
| 742 | mgs_add_common_pgpcert_vars(r, ctxt->sc->cert_pgp, 0, | ||
| 688 | ctxt->sc->export_certificates_enabled); | 743 | ctxt->sc->export_certificates_enabled); |
| 689 | 744 | ||
| 690 | return rv; | 745 | return rv; |
| @@ -746,7 +801,7 @@ int mgs_hook_authz(request_rec * r) | |||
| 746 | */ | 801 | */ |
| 747 | #define MGS_SIDE ((side==0)?"SSL_SERVER":"SSL_CLIENT") | 802 | #define MGS_SIDE ((side==0)?"SSL_SERVER":"SSL_CLIENT") |
| 748 | static void | 803 | static void |
| 749 | mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt cert, int side, | 804 | mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert, int side, |
| 750 | int export_certificates_enabled) | 805 | int export_certificates_enabled) |
| 751 | { | 806 | { |
| 752 | unsigned char sbuf[64]; /* buffer to hold serials */ | 807 | unsigned char sbuf[64]; /* buffer to hold serials */ |
| @@ -852,17 +907,82 @@ mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt cert, int side, | |||
| 852 | } | 907 | } |
| 853 | } | 908 | } |
| 854 | } | 909 | } |
| 910 | } | ||
| 855 | 911 | ||
| 912 | static void | ||
| 913 | mgs_add_common_pgpcert_vars(request_rec * r, gnutls_openpgp_crt_t cert, int side, | ||
| 914 | int export_certificates_enabled) | ||
| 915 | { | ||
| 916 | unsigned char sbuf[64]; /* buffer to hold serials */ | ||
| 917 | char buf[AP_IOBUFSIZE]; | ||
| 918 | const char *tmp; | ||
| 919 | size_t len; | ||
| 920 | int ret; | ||
| 856 | 921 | ||
| 857 | } | 922 | apr_table_t *env = r->subprocess_env; |
| 923 | |||
| 924 | if (export_certificates_enabled != 0) { | ||
| 925 | char cert_buf[10 * 1024]; | ||
| 926 | len = sizeof(cert_buf); | ||
| 927 | |||
| 928 | if (gnutls_openpgp_crt_export | ||
| 929 | (cert, GNUTLS_OPENPGP_FMT_BASE64, cert_buf, &len) >= 0) | ||
| 930 | apr_table_setn(env, | ||
| 931 | apr_pstrcat(r->pool, MGS_SIDE, "_CERT", NULL), | ||
| 932 | apr_pstrmemdup(r->pool, cert_buf, len)); | ||
| 933 | |||
| 934 | } | ||
| 935 | |||
| 936 | len = sizeof(buf); | ||
| 937 | gnutls_openpgp_crt_get_name(cert, 0, buf, &len); | ||
| 938 | apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_NAME", NULL), | ||
| 939 | apr_pstrmemdup(r->pool, buf, len)); | ||
| 940 | |||
| 941 | len = sizeof(sbuf); | ||
| 942 | gnutls_openpgp_crt_get_fingerprint(cert, sbuf, &len); | ||
| 943 | tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf)); | ||
| 944 | apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_FINGERPRINT", NULL), | ||
| 945 | apr_pstrdup(r->pool, tmp)); | ||
| 946 | |||
| 947 | ret = gnutls_openpgp_crt_get_version(cert); | ||
| 948 | if (ret > 0) | ||
| 949 | apr_table_setn(env, | ||
| 950 | apr_pstrcat(r->pool, MGS_SIDE, "_M_VERSION", NULL), | ||
| 951 | apr_psprintf(r->pool, "%u", ret)); | ||
| 952 | |||
| 953 | apr_table_setn(env, | ||
| 954 | apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL), "OPENPGP"); | ||
| 955 | |||
| 956 | tmp = | ||
| 957 | mgs_time2sz(gnutls_openpgp_crt_get_expiration_time | ||
| 958 | (cert), buf, sizeof(buf)); | ||
| 959 | apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL), | ||
| 960 | apr_pstrdup(r->pool, tmp)); | ||
| 858 | 961 | ||
| 962 | tmp = | ||
| 963 | mgs_time2sz(gnutls_openpgp_crt_get_creation_time | ||
| 964 | (cert), buf, sizeof(buf)); | ||
| 965 | apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL), | ||
| 966 | apr_pstrdup(r->pool, tmp)); | ||
| 859 | 967 | ||
| 968 | ret = gnutls_openpgp_crt_get_pk_algorithm(cert, NULL); | ||
| 969 | if (ret >= 0) { | ||
| 970 | apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY", NULL), | ||
| 971 | gnutls_pk_algorithm_get_name(ret)); | ||
| 972 | } | ||
| 973 | |||
| 974 | } | ||
| 975 | |||
| 976 | /* FIXME: Allow client sending a certificate chain */ | ||
| 860 | static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt) | 977 | static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt) |
| 861 | { | 978 | { |
| 862 | const gnutls_datum_t *cert_list; | 979 | const gnutls_datum_t *cert_list; |
| 863 | unsigned int cert_list_size, status, expired; | 980 | unsigned int cert_list_size, status, expired; |
| 864 | int rv, ret; | 981 | int rv, ret; |
| 865 | gnutls_x509_crt_t cert; | 982 | union { |
| 983 | gnutls_x509_crt_t x509; | ||
| 984 | gnutls_openpgp_crt_t pgp; | ||
| 985 | } cert; | ||
| 866 | apr_time_t activation_time, expiration_time, cur_time; | 986 | apr_time_t activation_time, expiration_time, cur_time; |
| 867 | 987 | ||
| 868 | cert_list = | 988 | cert_list = |
| @@ -888,23 +1008,40 @@ static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt) | |||
| 888 | return HTTP_FORBIDDEN; | 1008 | return HTTP_FORBIDDEN; |
| 889 | } | 1009 | } |
| 890 | 1010 | ||
| 891 | gnutls_x509_crt_init(&cert); | 1011 | if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509) { |
| 892 | rv = gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER); | 1012 | gnutls_x509_crt_init(&cert.x509); |
| 1013 | rv = gnutls_x509_crt_import(cert.x509, &cert_list[0], GNUTLS_X509_FMT_DER); | ||
| 1014 | } else if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_OPENPGP) { | ||
| 1015 | gnutls_openpgp_crt_init(&cert.pgp); | ||
| 1016 | rv = gnutls_openpgp_crt_import(cert.pgp, &cert_list[0], GNUTLS_OPENPGP_FMT_RAW); | ||
| 1017 | } else return HTTP_FORBIDDEN; | ||
| 1018 | |||
| 893 | if (rv < 0) { | 1019 | if (rv < 0) { |
| 894 | ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, | 1020 | ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, |
| 895 | "GnuTLS: Failed to Verify Peer: " | 1021 | "GnuTLS: Failed to Verify Peer: " |
| 896 | "Failed to import peer certificates."); | 1022 | "Failed to import peer certificates."); |
| 897 | ret = HTTP_FORBIDDEN; | 1023 | ret = HTTP_FORBIDDEN; |
| 898 | goto exit; | 1024 | goto exit; |
| 899 | } | 1025 | } |
| 900 | 1026 | ||
| 901 | apr_time_ansi_put(&expiration_time, | 1027 | if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509) { |
| 902 | gnutls_x509_crt_get_expiration_time(cert)); | 1028 | apr_time_ansi_put(&expiration_time, |
| 903 | apr_time_ansi_put(&activation_time, | 1029 | gnutls_x509_crt_get_expiration_time(cert.x509)); |
| 904 | gnutls_x509_crt_get_activation_time(cert)); | 1030 | apr_time_ansi_put(&activation_time, |
| 1031 | gnutls_x509_crt_get_activation_time(cert.x509)); | ||
| 905 | 1032 | ||
| 906 | rv = gnutls_x509_crt_verify(cert, ctxt->sc->ca_list, | 1033 | rv = gnutls_x509_crt_verify(cert.x509, ctxt->sc->ca_list, |
| 907 | ctxt->sc->ca_list_size, 0, &status); | 1034 | ctxt->sc->ca_list_size, 0, &status); |
| 1035 | } else { | ||
| 1036 | apr_time_ansi_put(&expiration_time, | ||
| 1037 | gnutls_openpgp_crt_get_expiration_time(cert.pgp)); | ||
| 1038 | apr_time_ansi_put(&activation_time, | ||
| 1039 | gnutls_openpgp_crt_get_creation_time(cert.pgp)); | ||
| 1040 | |||
| 1041 | rv = gnutls_openpgp_crt_verify_ring(cert.pgp, ctxt->sc->pgp_list, | ||
| 1042 | 0, &status); | ||
| 1043 | } | ||
| 1044 | |||
| 908 | 1045 | ||
| 909 | if (rv < 0) { | 1046 | if (rv < 0) { |
| 910 | ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, | 1047 | ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, |
| @@ -957,7 +1094,11 @@ static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt) | |||
| 957 | // mgs_hook_fixups(r); | 1094 | // mgs_hook_fixups(r); |
| 958 | // rv = mgs_authz_lua(r); | 1095 | // rv = mgs_authz_lua(r); |
| 959 | 1096 | ||
| 960 | mgs_add_common_cert_vars(r, cert, 1, | 1097 | if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509) |
| 1098 | mgs_add_common_cert_vars(r, cert.x509, 1, | ||
| 1099 | ctxt->sc->export_certificates_enabled); | ||
| 1100 | else if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_OPENPGP) | ||
| 1101 | mgs_add_common_pgpcert_vars(r, cert.pgp, 1, | ||
| 961 | ctxt->sc->export_certificates_enabled); | 1102 | ctxt->sc->export_certificates_enabled); |
| 962 | 1103 | ||
| 963 | { | 1104 | { |
| @@ -981,7 +1122,10 @@ static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt) | |||
| 981 | } | 1122 | } |
| 982 | 1123 | ||
| 983 | exit: | 1124 | exit: |
| 984 | gnutls_x509_crt_deinit(cert); | 1125 | if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509) |
| 1126 | gnutls_x509_crt_deinit(cert.x509); | ||
| 1127 | else if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_OPENPGP) | ||
| 1128 | gnutls_openpgp_crt_deinit(cert.pgp); | ||
| 985 | return ret; | 1129 | return ret; |
| 986 | 1130 | ||
| 987 | 1131 | ||
diff --git a/src/mod_gnutls.c b/src/mod_gnutls.c index a6e5528..4d70fbd 100644 --- a/src/mod_gnutls.c +++ b/src/mod_gnutls.c | |||
| @@ -64,6 +64,10 @@ static const command_rec mgs_config_cmds[] = { | |||
| 64 | NULL, | 64 | NULL, |
| 65 | RSRC_CONF, | 65 | RSRC_CONF, |
| 66 | "Set the CA File to verify Client Certificates"), | 66 | "Set the CA File to verify Client Certificates"), |
| 67 | AP_INIT_TAKE1("GnuTLSPGPKeyringFile", mgs_set_keyring_file, | ||
| 68 | NULL, | ||
| 69 | RSRC_CONF, | ||
| 70 | "Set the Keyring File to verify Client Certificates"), | ||
| 67 | AP_INIT_TAKE1("GnuTLSDHFile", mgs_set_dh_file, | 71 | AP_INIT_TAKE1("GnuTLSDHFile", mgs_set_dh_file, |
| 68 | NULL, | 72 | NULL, |
| 69 | RSRC_CONF, | 73 | RSRC_CONF, |
| @@ -75,11 +79,19 @@ static const command_rec mgs_config_cmds[] = { | |||
| 75 | AP_INIT_TAKE1("GnuTLSCertificateFile", mgs_set_cert_file, | 79 | AP_INIT_TAKE1("GnuTLSCertificateFile", mgs_set_cert_file, |
| 76 | NULL, | 80 | NULL, |
| 77 | RSRC_CONF, | 81 | RSRC_CONF, |
| 78 | "SSL Server Key file"), | 82 | "SSL Server Certificate file"), |
| 79 | AP_INIT_TAKE1("GnuTLSKeyFile", mgs_set_key_file, | 83 | AP_INIT_TAKE1("GnuTLSKeyFile", mgs_set_key_file, |
| 80 | NULL, | 84 | NULL, |
| 81 | RSRC_CONF, | 85 | RSRC_CONF, |
| 82 | "SSL Server SRP Password file"), | 86 | "SSL Server Private Key file"), |
| 87 | AP_INIT_TAKE1("GnuTLSPGPCertificateFile", mgs_set_pgpcert_file, | ||
| 88 | NULL, | ||
| 89 | RSRC_CONF, | ||
| 90 | "SSL Server PGP Certificate file"), | ||
| 91 | AP_INIT_TAKE1("GnuTLSPGPKeyFile", mgs_set_pgpkey_file, | ||
| 92 | NULL, | ||
| 93 | RSRC_CONF, | ||
| 94 | "SSL Server PGP Private key file"), | ||
| 83 | AP_INIT_TAKE1("GnuTLSSRPPasswdFile", mgs_set_srp_tpasswd_file, | 95 | AP_INIT_TAKE1("GnuTLSSRPPasswdFile", mgs_set_srp_tpasswd_file, |
| 84 | NULL, | 96 | NULL, |
| 85 | RSRC_CONF, | 97 | RSRC_CONF, |
