Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit bd3a7f9

Browse files
committed
Issue #18379: SSLSocket.getpeercert() returns CA issuer AIA fields, OCSP
and CRL distribution points.
1 parent efff706 commit bd3a7f9

4 files changed

Lines changed: 165 additions & 2 deletions

File tree

Doc/library/ssl.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,10 @@ SSL sockets also have the following additional methods and attributes:
733733
.. versionchanged:: 3.4
734734
:exc:`ValueError` is raised when the handshake isn't done.
735735

736+
.. versionchanged:: 3.4
737+
The returned dictionary includes additional X509v3 extension items
738+
such as ``crlDistributionPoints``, ``caIssuers`` and ``OCSP`` URIs.
739+
736740
.. method:: SSLSocket.cipher()
737741

738742
Returns a three-value tuple containing the name of the cipher being used, the

Lib/test/test_ssl.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,12 @@ def test_parse_cert(self):
212212
(('DNS', 'projects.developer.nokia.com'),
213213
('DNS', 'projects.forum.nokia.com'))
214214
)
215+
# extra OCSP and AIA fields
216+
self.assertEqual(p['OCSP'], ('http://ocsp.verisign.com',))
217+
self.assertEqual(p['caIssuers'],
218+
('http://SVRIntl-G3-aia.verisign.com/SVRIntlG3.cer',))
219+
self.assertEqual(p['crlDistributionPoints'],
220+
('http://SVRIntl-G3-crl.verisign.com/SVRIntlG3.crl',))
215221

216222
def test_parse_cert_CVE_2013_4238(self):
217223
p = ssl._ssl._test_decode_cert(NULLBYTECERT)
@@ -905,6 +911,7 @@ def test_get_ca_certs(self):
905911
'notAfter': asn1time('Mar 29 12:29:49 2033 GMT'),
906912
'notBefore': asn1time('Mar 30 12:29:49 2003 GMT'),
907913
'serialNumber': '00',
914+
'crlDistributionPoints': ('https://www.cacert.org/revoke.crl',),
908915
'subject': ((('organizationName', 'Root CA'),),
909916
(('organizationalUnitName', 'http://www.cacert.org'),),
910917
(('commonName', 'CA Cert Signing Authority'),),
@@ -1269,7 +1276,6 @@ def test_get_ca_certs_capath(self):
12691276
s.close()
12701277
self.assertEqual(len(ctx.get_ca_certs()), 1)
12711278

1272-
12731279
try:
12741280
import threading
12751281
except ImportError:

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ Core and Builtins
5959
Library
6060
-------
6161

62+
- Issue #18379: SSLSocket.getpeercert() returns CA issuer AIA fields, OCSP
63+
and CRL distribution points.
64+
6265
- Issue #18138: Implement cadata argument of SSLContext.load_verify_location()
6366
to load CA certificates and CRL from memory. It supports PEM and DER
6467
encoded strings.

Modules/_ssl.c

Lines changed: 151 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -964,6 +964,120 @@ _get_peer_alt_names (X509 *certificate) {
964964
return NULL;
965965
}
966966

967+
static PyObject *
968+
_get_aia_uri(X509 *certificate, int nid) {
969+
PyObject *lst = NULL, *ostr = NULL;
970+
int i, result;
971+
AUTHORITY_INFO_ACCESS *info;
972+
973+
info = X509_get_ext_d2i(certificate, NID_info_access, NULL, NULL);
974+
if ((info == NULL) || (sk_ACCESS_DESCRIPTION_num(info) == 0)) {
975+
return Py_None;
976+
}
977+
978+
if ((lst = PyList_New(0)) == NULL) {
979+
goto fail;
980+
}
981+
982+
for (i = 0; i < sk_ACCESS_DESCRIPTION_num(info); i++) {
983+
ACCESS_DESCRIPTION *ad = sk_ACCESS_DESCRIPTION_value(info, i);
984+
ASN1_IA5STRING *uri;
985+
986+
if ((OBJ_obj2nid(ad->method) != nid) ||
987+
(ad->location->type != GEN_URI)) {
988+
continue;
989+
}
990+
uri = ad->location->d.uniformResourceIdentifier;
991+
ostr = PyUnicode_FromStringAndSize((char *)uri->data,
992+
uri->length);
993+
if (ostr == NULL) {
994+
goto fail;
995+
}
996+
result = PyList_Append(lst, ostr);
997+
Py_DECREF(ostr);
998+
if (result < 0) {
999+
goto fail;
1000+
}
1001+
}
1002+
AUTHORITY_INFO_ACCESS_free(info);
1003+
1004+
/* convert to tuple or None */
1005+
if (PyList_Size(lst) == 0) {
1006+
Py_DECREF(lst);
1007+
return Py_None;
1008+
} else {
1009+
PyObject *tup;
1010+
tup = PyList_AsTuple(lst);
1011+
Py_DECREF(lst);
1012+
return tup;
1013+
}
1014+
1015+
fail:
1016+
AUTHORITY_INFO_ACCESS_free(info);
1017+
Py_DECREF(lst);
1018+
return NULL;
1019+
}
1020+
1021+
static PyObject *
1022+
_get_crl_dp(X509 *certificate) {
1023+
STACK_OF(DIST_POINT) *dps;
1024+
int i, j, result;
1025+
PyObject *lst;
1026+
1027+
/* Calls x509v3_cache_extensions and sets up crldp */
1028+
X509_check_ca(certificate);
1029+
dps = certificate->crldp;
1030+
if (dps == NULL) {
1031+
return Py_None;
1032+
}
1033+
1034+
if ((lst = PyList_New(0)) == NULL) {
1035+
return NULL;
1036+
}
1037+
1038+
for (i=0; i < sk_DIST_POINT_num(dps); i++) {
1039+
DIST_POINT *dp;
1040+
STACK_OF(GENERAL_NAME) *gns;
1041+
1042+
dp = sk_DIST_POINT_value(dps, i);
1043+
gns = dp->distpoint->name.fullname;
1044+
1045+
for (j=0; j < sk_GENERAL_NAME_num(gns); j++) {
1046+
GENERAL_NAME *gn;
1047+
ASN1_IA5STRING *uri;
1048+
PyObject *ouri;
1049+
1050+
gn = sk_GENERAL_NAME_value(gns, j);
1051+
if (gn->type != GEN_URI) {
1052+
continue;
1053+
}
1054+
uri = gn->d.uniformResourceIdentifier;
1055+
ouri = PyUnicode_FromStringAndSize((char *)uri->data,
1056+
uri->length);
1057+
if (ouri == NULL) {
1058+
Py_DECREF(lst);
1059+
return NULL;
1060+
}
1061+
result = PyList_Append(lst, ouri);
1062+
Py_DECREF(ouri);
1063+
if (result < 0) {
1064+
Py_DECREF(lst);
1065+
return NULL;
1066+
}
1067+
}
1068+
}
1069+
/* convert to tuple or None */
1070+
if (PyList_Size(lst) == 0) {
1071+
Py_DECREF(lst);
1072+
return Py_None;
1073+
} else {
1074+
PyObject *tup;
1075+
tup = PyList_AsTuple(lst);
1076+
Py_DECREF(lst);
1077+
return tup;
1078+
}
1079+
}
1080+
9671081
static PyObject *
9681082
_decode_certificate(X509 *certificate) {
9691083

@@ -974,9 +1088,10 @@ _decode_certificate(X509 *certificate) {
9741088
PyObject *issuer;
9751089
PyObject *version;
9761090
PyObject *sn_obj;
1091+
PyObject *obj;
9771092
ASN1_INTEGER *serialNumber;
9781093
char buf[2048];
979-
int len;
1094+
int len, result;
9801095
ASN1_TIME *notBefore, *notAfter;
9811096
PyObject *pnotBefore, *pnotAfter;
9821097

@@ -1082,6 +1197,41 @@ _decode_certificate(X509 *certificate) {
10821197
Py_DECREF(peer_alt_names);
10831198
}
10841199

1200+
/* Authority Information Access: OCSP URIs */
1201+
obj = _get_aia_uri(certificate, NID_ad_OCSP);
1202+
if (obj == NULL) {
1203+
goto fail1;
1204+
} else if (obj != Py_None) {
1205+
result = PyDict_SetItemString(retval, "OCSP", obj);
1206+
Py_DECREF(obj);
1207+
if (result < 0) {
1208+
goto fail1;
1209+
}
1210+
}
1211+
1212+
obj = _get_aia_uri(certificate, NID_ad_ca_issuers);
1213+
if (obj == NULL) {
1214+
goto fail1;
1215+
} else if (obj != Py_None) {
1216+
result = PyDict_SetItemString(retval, "caIssuers", obj);
1217+
Py_DECREF(obj);
1218+
if (result < 0) {
1219+
goto fail1;
1220+
}
1221+
}
1222+
1223+
/* CDP (CRL distribution points) */
1224+
obj = _get_crl_dp(certificate);
1225+
if (obj == NULL) {
1226+
goto fail1;
1227+
} else if (obj != Py_None) {
1228+
result = PyDict_SetItemString(retval, "crlDistributionPoints", obj);
1229+
Py_DECREF(obj);
1230+
if (result < 0) {
1231+
goto fail1;
1232+
}
1233+
}
1234+
10851235
BIO_free(biobuf);
10861236
return retval;
10871237

0 commit comments

Comments
 (0)