comparison src/mail/ngx_mail_auth_http_module.c @ 5989:ec01b1d1fff1

Mail: client SSL certificates support. The "ssl_verify_client", "ssl_verify_depth", "ssl_client_certificate", "ssl_trusted_certificate", and "ssl_crl" directives introduced to control SSL client certificate verification in mail proxy module. If there is a certificate, detail of the certificate are passed to the auth_http script configured via Auth-SSL-Verify, Auth-SSL-Subject, Auth-SSL-Issuer, Auth-SSL-Serial, Auth-SSL-Fingerprint headers. If the auth_http_pass_client_cert directive is set, client certificate in PEM format will be passed in the Auth-SSL-Cert header (urlencoded). If there is no required certificate provided during an SSL handshake or certificate verification fails then a protocol-specific error is returned after the SSL handshake and the connection is closed. Based on previous work by Sven Peter, Franck Levionnois and Filipe Da Silva.
author Maxim Dounin <mdounin@mdounin.ru>
date Wed, 25 Feb 2015 17:48:05 +0300
parents 3b3f789655dc
children 6a7c6973d6fc
comparison
equal deleted inserted replaced
5988:3b3f789655dc 5989:ec01b1d1fff1
14 14
15 typedef struct { 15 typedef struct {
16 ngx_addr_t *peer; 16 ngx_addr_t *peer;
17 17
18 ngx_msec_t timeout; 18 ngx_msec_t timeout;
19 ngx_flag_t pass_client_cert;
19 20
20 ngx_str_t host_header; 21 ngx_str_t host_header;
21 ngx_str_t uri; 22 ngx_str_t uri;
22 ngx_str_t header; 23 ngx_str_t header;
23 24
104 ngx_mail_auth_http_header, 105 ngx_mail_auth_http_header,
105 NGX_MAIL_SRV_CONF_OFFSET, 106 NGX_MAIL_SRV_CONF_OFFSET,
106 0, 107 0,
107 NULL }, 108 NULL },
108 109
110 { ngx_string("auth_http_pass_client_cert"),
111 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
112 ngx_conf_set_flag_slot,
113 NGX_MAIL_SRV_CONF_OFFSET,
114 offsetof(ngx_mail_auth_http_conf_t, pass_client_cert),
115 NULL },
116
109 ngx_null_command 117 ngx_null_command
110 }; 118 };
111 119
112 120
113 static ngx_mail_module_t ngx_mail_auth_http_module_ctx = { 121 static ngx_mail_module_t ngx_mail_auth_http_module_ctx = {
1141 ngx_mail_auth_http_conf_t *ahcf) 1149 ngx_mail_auth_http_conf_t *ahcf)
1142 { 1150 {
1143 size_t len; 1151 size_t len;
1144 ngx_buf_t *b; 1152 ngx_buf_t *b;
1145 ngx_str_t login, passwd; 1153 ngx_str_t login, passwd;
1154 #if (NGX_MAIL_SSL)
1155 ngx_str_t verify, subject, issuer, serial, fingerprint,
1156 raw_cert, cert;
1157 ngx_connection_t *c;
1158 #endif
1146 ngx_mail_core_srv_conf_t *cscf; 1159 ngx_mail_core_srv_conf_t *cscf;
1147 1160
1148 if (ngx_mail_auth_http_escape(pool, &s->login, &login) != NGX_OK) { 1161 if (ngx_mail_auth_http_escape(pool, &s->login, &login) != NGX_OK) {
1149 return NULL; 1162 return NULL;
1150 } 1163 }
1151 1164
1152 if (ngx_mail_auth_http_escape(pool, &s->passwd, &passwd) != NGX_OK) { 1165 if (ngx_mail_auth_http_escape(pool, &s->passwd, &passwd) != NGX_OK) {
1153 return NULL; 1166 return NULL;
1154 } 1167 }
1168
1169 #if (NGX_MAIL_SSL)
1170
1171 c = s->connection;
1172
1173 if (c->ssl) {
1174
1175 /* certificate details */
1176
1177 if (ngx_ssl_get_client_verify(c, pool, &verify) != NGX_OK) {
1178 return NULL;
1179 }
1180
1181 if (ngx_ssl_get_subject_dn(c, pool, &subject) != NGX_OK) {
1182 return NULL;
1183 }
1184
1185 if (ngx_ssl_get_issuer_dn(c, pool, &issuer) != NGX_OK) {
1186 return NULL;
1187 }
1188
1189 if (ngx_ssl_get_serial_number(c, pool, &serial) != NGX_OK) {
1190 return NULL;
1191 }
1192
1193 if (ngx_ssl_get_fingerprint(c, pool, &fingerprint) != NGX_OK) {
1194 return NULL;
1195 }
1196
1197 if (ahcf->pass_client_cert) {
1198
1199 /* certificate itself, if configured */
1200
1201 if (ngx_ssl_get_raw_certificate(c, pool, &raw_cert) != NGX_OK) {
1202 return NULL;
1203 }
1204
1205 if (ngx_mail_auth_http_escape(pool, &raw_cert, &cert) != NGX_OK) {
1206 return NULL;
1207 }
1208
1209 } else {
1210 ngx_str_null(&cert);
1211 }
1212
1213 } else {
1214 ngx_str_null(&verify);
1215 ngx_str_null(&subject);
1216 ngx_str_null(&issuer);
1217 ngx_str_null(&serial);
1218 ngx_str_null(&fingerprint);
1219 ngx_str_null(&cert);
1220 }
1221
1222 #endif
1155 1223
1156 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); 1224 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
1157 1225
1158 len = sizeof("GET ") - 1 + ahcf->uri.len + sizeof(" HTTP/1.0" CRLF) - 1 1226 len = sizeof("GET ") - 1 + ahcf->uri.len + sizeof(" HTTP/1.0" CRLF) - 1
1159 + sizeof("Host: ") - 1 + ahcf->host_header.len + sizeof(CRLF) - 1 1227 + sizeof("Host: ") - 1 + ahcf->host_header.len + sizeof(CRLF) - 1
1173 + sizeof("Auth-SMTP-Helo: ") - 1 + s->smtp_helo.len + sizeof(CRLF) - 1 1241 + sizeof("Auth-SMTP-Helo: ") - 1 + s->smtp_helo.len + sizeof(CRLF) - 1
1174 + sizeof("Auth-SMTP-From: ") - 1 + s->smtp_from.len + sizeof(CRLF) - 1 1242 + sizeof("Auth-SMTP-From: ") - 1 + s->smtp_from.len + sizeof(CRLF) - 1
1175 + sizeof("Auth-SMTP-To: ") - 1 + s->smtp_to.len + sizeof(CRLF) - 1 1243 + sizeof("Auth-SMTP-To: ") - 1 + s->smtp_to.len + sizeof(CRLF) - 1
1176 #if (NGX_MAIL_SSL) 1244 #if (NGX_MAIL_SSL)
1177 + sizeof("Auth-SSL: on" CRLF) - 1 1245 + sizeof("Auth-SSL: on" CRLF) - 1
1246 + sizeof("Auth-SSL-Verify: ") - 1 + verify.len + sizeof(CRLF) - 1
1247 + sizeof("Auth-SSL-Subject: ") - 1 + subject.len + sizeof(CRLF) - 1
1248 + sizeof("Auth-SSL-Issuer: ") - 1 + issuer.len + sizeof(CRLF) - 1
1249 + sizeof("Auth-SSL-Serial: ") - 1 + serial.len + sizeof(CRLF) - 1
1250 + sizeof("Auth-SSL-Fingerprint: ") - 1 + fingerprint.len
1251 + sizeof(CRLF) - 1
1252 + sizeof("Auth-SSL-Cert: ") - 1 + cert.len + sizeof(CRLF) - 1
1178 #endif 1253 #endif
1179 + ahcf->header.len 1254 + ahcf->header.len
1180 + sizeof(CRLF) - 1; 1255 + sizeof(CRLF) - 1;
1181 1256
1182 b = ngx_create_temp_buf(pool, len); 1257 b = ngx_create_temp_buf(pool, len);
1258 1333
1259 } 1334 }
1260 1335
1261 #if (NGX_MAIL_SSL) 1336 #if (NGX_MAIL_SSL)
1262 1337
1263 if (s->connection->ssl) { 1338 if (c->ssl) {
1264 b->last = ngx_cpymem(b->last, "Auth-SSL: on" CRLF, 1339 b->last = ngx_cpymem(b->last, "Auth-SSL: on" CRLF,
1265 sizeof("Auth-SSL: on" CRLF) - 1); 1340 sizeof("Auth-SSL: on" CRLF) - 1);
1341
1342 b->last = ngx_cpymem(b->last, "Auth-SSL-Verify: ",
1343 sizeof("Auth-SSL-Verify: ") - 1);
1344 b->last = ngx_copy(b->last, verify.data, verify.len);
1345 *b->last++ = CR; *b->last++ = LF;
1346
1347 if (subject.len) {
1348 b->last = ngx_cpymem(b->last, "Auth-SSL-Subject: ",
1349 sizeof("Auth-SSL-Subject: ") - 1);
1350 b->last = ngx_copy(b->last, subject.data, subject.len);
1351 *b->last++ = CR; *b->last++ = LF;
1352 }
1353
1354 if (issuer.len) {
1355 b->last = ngx_cpymem(b->last, "Auth-SSL-Issuer: ",
1356 sizeof("Auth-SSL-Issuer: ") - 1);
1357 b->last = ngx_copy(b->last, issuer.data, issuer.len);
1358 *b->last++ = CR; *b->last++ = LF;
1359 }
1360
1361 if (serial.len) {
1362 b->last = ngx_cpymem(b->last, "Auth-SSL-Serial: ",
1363 sizeof("Auth-SSL-Serial: ") - 1);
1364 b->last = ngx_copy(b->last, serial.data, serial.len);
1365 *b->last++ = CR; *b->last++ = LF;
1366 }
1367
1368 if (fingerprint.len) {
1369 b->last = ngx_cpymem(b->last, "Auth-SSL-Fingerprint: ",
1370 sizeof("Auth-SSL-Fingerprint: ") - 1);
1371 b->last = ngx_copy(b->last, fingerprint.data, fingerprint.len);
1372 *b->last++ = CR; *b->last++ = LF;
1373 }
1374
1375 if (cert.len) {
1376 b->last = ngx_cpymem(b->last, "Auth-SSL-Cert: ",
1377 sizeof("Auth-SSL-Cert: ") - 1);
1378 b->last = ngx_copy(b->last, cert.data, cert.len);
1379 *b->last++ = CR; *b->last++ = LF;
1380 }
1266 } 1381 }
1267 1382
1268 #endif 1383 #endif
1269 1384
1270 if (ahcf->header.len) { 1385 if (ahcf->header.len) {
1326 if (ahcf == NULL) { 1441 if (ahcf == NULL) {
1327 return NULL; 1442 return NULL;
1328 } 1443 }
1329 1444
1330 ahcf->timeout = NGX_CONF_UNSET_MSEC; 1445 ahcf->timeout = NGX_CONF_UNSET_MSEC;
1446 ahcf->pass_client_cert = NGX_CONF_UNSET;
1331 1447
1332 ahcf->file = cf->conf_file->file.name.data; 1448 ahcf->file = cf->conf_file->file.name.data;
1333 ahcf->line = cf->conf_file->line; 1449 ahcf->line = cf->conf_file->line;
1334 1450
1335 return ahcf; 1451 return ahcf;
1361 } 1477 }
1362 } 1478 }
1363 1479
1364 ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000); 1480 ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000);
1365 1481
1482 ngx_conf_merge_value(conf->pass_client_cert, prev->pass_client_cert, 0);
1483
1366 if (conf->headers == NULL) { 1484 if (conf->headers == NULL) {
1367 conf->headers = prev->headers; 1485 conf->headers = prev->headers;
1368 conf->header = prev->header; 1486 conf->header = prev->header;
1369 } 1487 }
1370 1488