summaryrefslogtreecommitdiffstatsabout
path: root/src/gnutls_hooks.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gnutls_hooks.c')
-rw-r--r--src/gnutls_hooks.c220
1 files changed, 182 insertions, 38 deletions
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
37static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt); 37static 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 */
39static void mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt cert, 39static void mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert,
40 int side,
41 int export_certificates_enabled);
42static 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 */
91const static int cert_type_prio[2] = { GNUTLS_CRT_X509, 0 };
92
93static int mgs_select_virtual_server_cb(gnutls_session_t session) 97static 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
155const char static_dh_params[] = "-----BEGIN DH PARAMETERS-----\n" 187const 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 */
169static int read_crt_cn(server_rec * s, apr_pool_t * p, 201static 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
252static 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
220int 277int
221mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog, 278mgs_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")
748static void 803static void
749mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt cert, int side, 804mgs_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
912static void
913mgs_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 */
860static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt) 977static 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