Changeset 832182b in mod_gnutls
- Timestamp:
- Nov 16, 2013, 2:46:50 AM (9 years ago)
- Branches:
- asyncio, debian/master, debian/stretch-backports, jessie-backports, main, master, proxy-ticket, upstream
- Children:
- a01f8ab
- Parents:
- 140d237
- git-author:
- Daniel Kahn Gillmor <dkg@…> (02/01/13 05:15:50)
- git-committer:
- Daniel Kahn Gillmor <dkg@…> (11/16/13 02:46:50)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/gnutls_hooks.c
r140d237 r832182b 40 40 static void mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert, int side, int export_full_cert); 41 41 static void mgs_add_common_pgpcert_vars(request_rec * r, gnutls_openpgp_crt_t cert, int side, int export_full_cert); 42 static const char* mgs_x509_construct_uid(request_rec * pool, gnutls_x509_crt_t cert); 42 43 43 44 /* Pool Cleanup Function */ … … 1204 1205 char* ptr = cert_pem_buf; 1205 1206 char* outptr = cert_pem_buf2; 1207 const char* candidate = mgs_x509_construct_uid(r, cert.x509[0]); 1206 1208 /* convert PEM to JSON-friendly string by escaping all newlines 1207 1209 (this should really be done within libmsv) */ … … 1214 1216 1215 1217 /* FIXME : put together a name from the cert we received, instead of hard-coding this value: */ 1216 rv = msv_query_agent(NULL, "https", "client", "Test User <test0@modgnutls.test>", "x509pem", cert_pem_buf2, &resp);1218 rv = msv_query_agent(NULL, "https", "client", candidate, "x509pem", cert_pem_buf2, &resp); 1217 1219 if (rv == LIBMSV_ERROR_SUCCESS) { 1218 1220 status = 0; … … 1355 1357 1356 1358 } 1359 1360 static const char* mgs_x509_leaf_oid_from_dn(apr_pool_t *pool, const char* oid, gnutls_x509_crt_t cert) { 1361 int rv=GNUTLS_E_SUCCESS, i; 1362 size_t sz=0, lastsz=0; 1363 char* data=NULL; 1364 1365 i = -1; 1366 while(rv != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { 1367 i++; 1368 lastsz=sz; 1369 sz=0; 1370 rv = gnutls_x509_crt_get_dn_by_oid (cert, oid, i, 0, NULL, &sz); 1371 } 1372 if (i > 0) { 1373 data = apr_palloc(pool, lastsz); 1374 sz=lastsz; 1375 rv = gnutls_x509_crt_get_dn_by_oid (cert, oid, i-1, 0, data, &sz); 1376 if (rv == GNUTLS_E_SUCCESS) 1377 return data; 1378 } 1379 return NULL; 1380 } 1381 1382 static const char* mgs_x509_first_type_from_san(apr_pool_t *pool, gnutls_x509_subject_alt_name_t target, gnutls_x509_crt_t cert) { 1383 int rv=GNUTLS_E_SUCCESS; 1384 size_t sz; 1385 char* data=NULL; 1386 unsigned int i; 1387 gnutls_x509_subject_alt_name_t thistype; 1388 1389 i = 0; 1390 while(rv != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { 1391 sz = 0; 1392 rv = gnutls_x509_crt_get_subject_alt_name2(cert, i, NULL, &sz, &thistype, NULL); 1393 if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && thistype == target) { 1394 data = apr_palloc(pool, sz); 1395 rv = gnutls_x509_crt_get_subject_alt_name2(cert, i, data, &sz, &thistype, NULL); 1396 if (rv == target) 1397 return data; 1398 } 1399 i++; 1400 } 1401 return NULL; 1402 } 1403 1404 /* Create a string representing a candidate User ID from an X.509 1405 * certificate 1406 1407 * We need this for client certification because a client gives us a 1408 * certificate, but doesn't tell us (in any other way) who they are 1409 * trying to authenticate as. 1410 1411 * TODO: we might need another parallel for OpenPGP, but for that it's 1412 * much simpler: we can just assume that the first User ID marked as 1413 * "primary" (or the first User ID, period) is the identity the user 1414 * is trying to present as. 1415 1416 * one complaint might be "but the user wanted to be another identity, 1417 * which is also in the certificate (e.g. in a SubjectAltName)" 1418 * However, given that any user can regenerate their own X.509 1419 * certificate with their own public key content, they should just do 1420 * so, and not expect us to guess at their identity :) 1421 1422 * This function allocates it's response from the pool given it. When 1423 * that pool is reclaimed, the response will also be deallocated. 1424 1425 * FIXME: what about extracting a server-style cert 1426 * (e.g. https://imposter.example) from the DN or any sAN? 1427 1428 * FIXME: what if we want to call this outside the context of a 1429 * request? That complicates the logging. 1430 */ 1431 static const char* mgs_x509_construct_uid(request_rec *r, gnutls_x509_crt_t cert) { 1432 /* basic strategy, assuming humans are the users: we are going to 1433 * try to reconstruct a "conventional" User ID by pulling in a 1434 * name, comment, and e-mail address. 1435 */ 1436 apr_pool_t *pool = r->pool; 1437 const char *name=NULL, *comment=NULL, *email=NULL; 1438 const char *ret=NULL; 1439 /* subpool for temporary allocation: */ 1440 apr_pool_t *sp=NULL; 1441 1442 if (APR_SUCCESS != apr_pool_create(&sp, pool)) 1443 return NULL; /* i'm assuming that libapr would log this kind 1444 * of error on its own */ 1445 1446 /* Name 1447 1448 the name comes from the leaf commonName of the cert's Subject. 1449 1450 (MAYBE: should we look at trying to assemble a candidate from 1451 givenName, surName, suffix, etc? the "name" field 1452 appears to be case-insensitive, which seems problematic 1453 from what we expect; see: 1454 http://www.itu.int/rec/T-REC-X.520-200102-s/e ) 1455 1456 (MAYBE: should we try pulling a commonName or otherName or 1457 something from subjectAltName? see: 1458 https://tools.ietf.org/html/rfc5280#section-4.2.1.6 1459 GnuTLS does not support looking for Common Names in the 1460 SAN yet) 1461 */ 1462 name = mgs_x509_leaf_oid_from_dn(sp, GNUTLS_OID_X520_COMMON_NAME, cert); 1463 1464 /* Comment 1465 1466 I am inclined to punt on this for now, as Comment has been so 1467 atrociously misused in OpenPGP. Perhaps if there is a 1468 pseudonym (OID 2.5.4.65, aka GNUTLS_OID_X520_PSEUDONYM) field 1469 in the subject or sAN? 1470 */ 1471 comment = mgs_x509_leaf_oid_from_dn(sp, GNUTLS_OID_X520_PSEUDONYM, cert); 1472 1473 /* E-mail 1474 1475 This should be the the first rfc822Name from the sAN. 1476 1477 (MAYBE: leaf rfc822Name in the certificate's subject, but this is 1478 deprecated, and i don't see the OID in x509.h; can we 1479 support it?) 1480 1481 */ 1482 email = mgs_x509_first_type_from_san(sp, GNUTLS_SAN_RFC822NAME, cert); 1483 1484 1485 /* assemble all the parts: */ 1486 1487 /* must have at least a name or an e-mail. */ 1488 if (name == NULL && email == NULL) { 1489 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1490 "GnuTLS: Need either a name or an e-mail address to get a User ID from an X.509 certificate."); 1491 goto end; 1492 } 1493 if (name) { 1494 if (comment) { 1495 if (email) { 1496 ret = apr_psprintf(pool, "%s (%s) <%s>", name, comment, email); 1497 } else { 1498 ret = apr_psprintf(pool, "%s (%s)", name, comment); 1499 } 1500 } else { 1501 if (email) { 1502 ret = apr_psprintf(pool, "%s <%s>", name, email); 1503 } else { 1504 ret = apr_pstrdup(pool, name); 1505 } 1506 } 1507 } else { 1508 if (comment) { 1509 ret = apr_psprintf(pool, "(%s) <%s>", comment, email); 1510 } else { 1511 ret = apr_psprintf(pool, "<%s>", email); 1512 } 1513 } 1514 1515 end: 1516 apr_pool_destroy(sp); 1517 return ret; 1518 }
Note: See TracChangeset
for help on using the changeset viewer.