1# This file is dual licensed under the terms of the Apache License, Version
2# 2.0, and the BSD License. See the LICENSE file in the root of this repository
3# for complete details.
4
5from __future__ import absolute_import, division, print_function
6
7import calendar
8import ipaddress
9
10import six
11
12from cryptography import utils, x509
13from cryptography.hazmat.backends.openssl.decode_asn1 import (
14    _CRL_ENTRY_REASON_ENUM_TO_CODE,
15    _DISTPOINT_TYPE_FULLNAME,
16    _DISTPOINT_TYPE_RELATIVENAME,
17)
18from cryptography.x509.name import _ASN1Type
19from cryptography.x509.oid import (
20    CRLEntryExtensionOID,
21    ExtensionOID,
22    OCSPExtensionOID,
23)
24
25
26def _encode_asn1_int(backend, x):
27    """
28    Converts a python integer to an ASN1_INTEGER. The returned ASN1_INTEGER
29    will not be garbage collected (to support adding them to structs that take
30    ownership of the object). Be sure to register it for GC if it will be
31    discarded after use.
32
33    """
34    # Convert Python integer to OpenSSL "bignum" in case value exceeds
35    # machine's native integer limits (note: `int_to_bn` doesn't automatically
36    # GC).
37    i = backend._int_to_bn(x)
38    i = backend._ffi.gc(i, backend._lib.BN_free)
39
40    # Wrap in an ASN.1 integer.  Don't GC -- as documented.
41    i = backend._lib.BN_to_ASN1_INTEGER(i, backend._ffi.NULL)
42    backend.openssl_assert(i != backend._ffi.NULL)
43    return i
44
45
46def _encode_asn1_int_gc(backend, x):
47    i = _encode_asn1_int(backend, x)
48    i = backend._ffi.gc(i, backend._lib.ASN1_INTEGER_free)
49    return i
50
51
52def _encode_asn1_str(backend, data):
53    """
54    Create an ASN1_OCTET_STRING from a Python byte string.
55    """
56    s = backend._lib.ASN1_OCTET_STRING_new()
57    res = backend._lib.ASN1_OCTET_STRING_set(s, data, len(data))
58    backend.openssl_assert(res == 1)
59    return s
60
61
62def _encode_asn1_utf8_str(backend, string):
63    """
64    Create an ASN1_UTF8STRING from a Python unicode string.
65    This object will be an ASN1_STRING with UTF8 type in OpenSSL and
66    can be decoded with ASN1_STRING_to_UTF8.
67    """
68    s = backend._lib.ASN1_UTF8STRING_new()
69    res = backend._lib.ASN1_STRING_set(
70        s, string.encode("utf8"), len(string.encode("utf8"))
71    )
72    backend.openssl_assert(res == 1)
73    return s
74
75
76def _encode_asn1_str_gc(backend, data):
77    s = _encode_asn1_str(backend, data)
78    s = backend._ffi.gc(s, backend._lib.ASN1_OCTET_STRING_free)
79    return s
80
81
82def _encode_inhibit_any_policy(backend, inhibit_any_policy):
83    return _encode_asn1_int_gc(backend, inhibit_any_policy.skip_certs)
84
85
86def _encode_name(backend, name):
87    """
88    The X509_NAME created will not be gc'd. Use _encode_name_gc if needed.
89    """
90    subject = backend._lib.X509_NAME_new()
91    for rdn in name.rdns:
92        set_flag = 0  # indicate whether to add to last RDN or create new RDN
93        for attribute in rdn:
94            name_entry = _encode_name_entry(backend, attribute)
95            # X509_NAME_add_entry dups the object so we need to gc this copy
96            name_entry = backend._ffi.gc(
97                name_entry, backend._lib.X509_NAME_ENTRY_free
98            )
99            res = backend._lib.X509_NAME_add_entry(
100                subject, name_entry, -1, set_flag
101            )
102            backend.openssl_assert(res == 1)
103            set_flag = -1
104    return subject
105
106
107def _encode_name_gc(backend, attributes):
108    subject = _encode_name(backend, attributes)
109    subject = backend._ffi.gc(subject, backend._lib.X509_NAME_free)
110    return subject
111
112
113def _encode_sk_name_entry(backend, attributes):
114    """
115    The sk_X509_NAME_ENTRY created will not be gc'd.
116    """
117    stack = backend._lib.sk_X509_NAME_ENTRY_new_null()
118    for attribute in attributes:
119        name_entry = _encode_name_entry(backend, attribute)
120        res = backend._lib.sk_X509_NAME_ENTRY_push(stack, name_entry)
121        backend.openssl_assert(res >= 1)
122    return stack
123
124
125def _encode_name_entry(backend, attribute):
126    if attribute._type is _ASN1Type.BMPString:
127        value = attribute.value.encode("utf_16_be")
128    elif attribute._type is _ASN1Type.UniversalString:
129        value = attribute.value.encode("utf_32_be")
130    else:
131        value = attribute.value.encode("utf8")
132
133    obj = _txt2obj_gc(backend, attribute.oid.dotted_string)
134
135    name_entry = backend._lib.X509_NAME_ENTRY_create_by_OBJ(
136        backend._ffi.NULL, obj, attribute._type.value, value, len(value)
137    )
138    return name_entry
139
140
141def _encode_crl_number_delta_crl_indicator(backend, ext):
142    return _encode_asn1_int_gc(backend, ext.crl_number)
143
144
145def _encode_issuing_dist_point(backend, ext):
146    idp = backend._lib.ISSUING_DIST_POINT_new()
147    backend.openssl_assert(idp != backend._ffi.NULL)
148    idp = backend._ffi.gc(idp, backend._lib.ISSUING_DIST_POINT_free)
149    idp.onlyuser = 255 if ext.only_contains_user_certs else 0
150    idp.onlyCA = 255 if ext.only_contains_ca_certs else 0
151    idp.indirectCRL = 255 if ext.indirect_crl else 0
152    idp.onlyattr = 255 if ext.only_contains_attribute_certs else 0
153    if ext.only_some_reasons:
154        idp.onlysomereasons = _encode_reasonflags(
155            backend, ext.only_some_reasons
156        )
157
158    if ext.full_name:
159        idp.distpoint = _encode_full_name(backend, ext.full_name)
160
161    if ext.relative_name:
162        idp.distpoint = _encode_relative_name(backend, ext.relative_name)
163
164    return idp
165
166
167def _encode_crl_reason(backend, crl_reason):
168    asn1enum = backend._lib.ASN1_ENUMERATED_new()
169    backend.openssl_assert(asn1enum != backend._ffi.NULL)
170    asn1enum = backend._ffi.gc(asn1enum, backend._lib.ASN1_ENUMERATED_free)
171    res = backend._lib.ASN1_ENUMERATED_set(
172        asn1enum, _CRL_ENTRY_REASON_ENUM_TO_CODE[crl_reason.reason]
173    )
174    backend.openssl_assert(res == 1)
175
176    return asn1enum
177
178
179def _encode_invalidity_date(backend, invalidity_date):
180    time = backend._lib.ASN1_GENERALIZEDTIME_set(
181        backend._ffi.NULL,
182        calendar.timegm(invalidity_date.invalidity_date.timetuple()),
183    )
184    backend.openssl_assert(time != backend._ffi.NULL)
185    time = backend._ffi.gc(time, backend._lib.ASN1_GENERALIZEDTIME_free)
186
187    return time
188
189
190def _encode_certificate_policies(backend, certificate_policies):
191    cp = backend._lib.sk_POLICYINFO_new_null()
192    backend.openssl_assert(cp != backend._ffi.NULL)
193    cp = backend._ffi.gc(cp, backend._lib.sk_POLICYINFO_free)
194    for policy_info in certificate_policies:
195        pi = backend._lib.POLICYINFO_new()
196        backend.openssl_assert(pi != backend._ffi.NULL)
197        res = backend._lib.sk_POLICYINFO_push(cp, pi)
198        backend.openssl_assert(res >= 1)
199        oid = _txt2obj(backend, policy_info.policy_identifier.dotted_string)
200        pi.policyid = oid
201        if policy_info.policy_qualifiers:
202            pqis = backend._lib.sk_POLICYQUALINFO_new_null()
203            backend.openssl_assert(pqis != backend._ffi.NULL)
204            for qualifier in policy_info.policy_qualifiers:
205                pqi = backend._lib.POLICYQUALINFO_new()
206                backend.openssl_assert(pqi != backend._ffi.NULL)
207                res = backend._lib.sk_POLICYQUALINFO_push(pqis, pqi)
208                backend.openssl_assert(res >= 1)
209                if isinstance(qualifier, six.text_type):
210                    pqi.pqualid = _txt2obj(
211                        backend, x509.OID_CPS_QUALIFIER.dotted_string
212                    )
213                    pqi.d.cpsuri = _encode_asn1_str(
214                        backend,
215                        qualifier.encode("ascii"),
216                    )
217                else:
218                    assert isinstance(qualifier, x509.UserNotice)
219                    pqi.pqualid = _txt2obj(
220                        backend, x509.OID_CPS_USER_NOTICE.dotted_string
221                    )
222                    un = backend._lib.USERNOTICE_new()
223                    backend.openssl_assert(un != backend._ffi.NULL)
224                    pqi.d.usernotice = un
225                    if qualifier.explicit_text:
226                        un.exptext = _encode_asn1_utf8_str(
227                            backend, qualifier.explicit_text
228                        )
229
230                    un.noticeref = _encode_notice_reference(
231                        backend, qualifier.notice_reference
232                    )
233
234            pi.qualifiers = pqis
235
236    return cp
237
238
239def _encode_notice_reference(backend, notice):
240    if notice is None:
241        return backend._ffi.NULL
242    else:
243        nr = backend._lib.NOTICEREF_new()
244        backend.openssl_assert(nr != backend._ffi.NULL)
245        # organization is a required field
246        nr.organization = _encode_asn1_utf8_str(backend, notice.organization)
247
248        notice_stack = backend._lib.sk_ASN1_INTEGER_new_null()
249        nr.noticenos = notice_stack
250        for number in notice.notice_numbers:
251            num = _encode_asn1_int(backend, number)
252            res = backend._lib.sk_ASN1_INTEGER_push(notice_stack, num)
253            backend.openssl_assert(res >= 1)
254
255        return nr
256
257
258def _txt2obj(backend, name):
259    """
260    Converts a Python string with an ASN.1 object ID in dotted form to a
261    ASN1_OBJECT.
262    """
263    name = name.encode("ascii")
264    obj = backend._lib.OBJ_txt2obj(name, 1)
265    backend.openssl_assert(obj != backend._ffi.NULL)
266    return obj
267
268
269def _txt2obj_gc(backend, name):
270    obj = _txt2obj(backend, name)
271    obj = backend._ffi.gc(obj, backend._lib.ASN1_OBJECT_free)
272    return obj
273
274
275def _encode_ocsp_nocheck(backend, ext):
276    # Doesn't need to be GC'd
277    return backend._lib.ASN1_NULL_new()
278
279
280def _encode_key_usage(backend, key_usage):
281    set_bit = backend._lib.ASN1_BIT_STRING_set_bit
282    ku = backend._lib.ASN1_BIT_STRING_new()
283    ku = backend._ffi.gc(ku, backend._lib.ASN1_BIT_STRING_free)
284    res = set_bit(ku, 0, key_usage.digital_signature)
285    backend.openssl_assert(res == 1)
286    res = set_bit(ku, 1, key_usage.content_commitment)
287    backend.openssl_assert(res == 1)
288    res = set_bit(ku, 2, key_usage.key_encipherment)
289    backend.openssl_assert(res == 1)
290    res = set_bit(ku, 3, key_usage.data_encipherment)
291    backend.openssl_assert(res == 1)
292    res = set_bit(ku, 4, key_usage.key_agreement)
293    backend.openssl_assert(res == 1)
294    res = set_bit(ku, 5, key_usage.key_cert_sign)
295    backend.openssl_assert(res == 1)
296    res = set_bit(ku, 6, key_usage.crl_sign)
297    backend.openssl_assert(res == 1)
298    if key_usage.key_agreement:
299        res = set_bit(ku, 7, key_usage.encipher_only)
300        backend.openssl_assert(res == 1)
301        res = set_bit(ku, 8, key_usage.decipher_only)
302        backend.openssl_assert(res == 1)
303    else:
304        res = set_bit(ku, 7, 0)
305        backend.openssl_assert(res == 1)
306        res = set_bit(ku, 8, 0)
307        backend.openssl_assert(res == 1)
308
309    return ku
310
311
312def _encode_authority_key_identifier(backend, authority_keyid):
313    akid = backend._lib.AUTHORITY_KEYID_new()
314    backend.openssl_assert(akid != backend._ffi.NULL)
315    akid = backend._ffi.gc(akid, backend._lib.AUTHORITY_KEYID_free)
316    if authority_keyid.key_identifier is not None:
317        akid.keyid = _encode_asn1_str(
318            backend,
319            authority_keyid.key_identifier,
320        )
321
322    if authority_keyid.authority_cert_issuer is not None:
323        akid.issuer = _encode_general_names(
324            backend, authority_keyid.authority_cert_issuer
325        )
326
327    if authority_keyid.authority_cert_serial_number is not None:
328        akid.serial = _encode_asn1_int(
329            backend, authority_keyid.authority_cert_serial_number
330        )
331
332    return akid
333
334
335def _encode_basic_constraints(backend, basic_constraints):
336    constraints = backend._lib.BASIC_CONSTRAINTS_new()
337    constraints = backend._ffi.gc(
338        constraints, backend._lib.BASIC_CONSTRAINTS_free
339    )
340    constraints.ca = 255 if basic_constraints.ca else 0
341    if basic_constraints.ca and basic_constraints.path_length is not None:
342        constraints.pathlen = _encode_asn1_int(
343            backend, basic_constraints.path_length
344        )
345
346    return constraints
347
348
349def _encode_information_access(backend, info_access):
350    aia = backend._lib.sk_ACCESS_DESCRIPTION_new_null()
351    backend.openssl_assert(aia != backend._ffi.NULL)
352    aia = backend._ffi.gc(
353        aia,
354        lambda x: backend._lib.sk_ACCESS_DESCRIPTION_pop_free(
355            x,
356            backend._ffi.addressof(
357                backend._lib._original_lib, "ACCESS_DESCRIPTION_free"
358            ),
359        ),
360    )
361    for access_description in info_access:
362        ad = backend._lib.ACCESS_DESCRIPTION_new()
363        method = _txt2obj(
364            backend, access_description.access_method.dotted_string
365        )
366        _encode_general_name_preallocated(
367            backend, access_description.access_location, ad.location
368        )
369        ad.method = method
370        res = backend._lib.sk_ACCESS_DESCRIPTION_push(aia, ad)
371        backend.openssl_assert(res >= 1)
372
373    return aia
374
375
376def _encode_general_names(backend, names):
377    general_names = backend._lib.GENERAL_NAMES_new()
378    backend.openssl_assert(general_names != backend._ffi.NULL)
379    for name in names:
380        gn = _encode_general_name(backend, name)
381        res = backend._lib.sk_GENERAL_NAME_push(general_names, gn)
382        backend.openssl_assert(res != 0)
383
384    return general_names
385
386
387def _encode_alt_name(backend, san):
388    general_names = _encode_general_names(backend, san)
389    general_names = backend._ffi.gc(
390        general_names, backend._lib.GENERAL_NAMES_free
391    )
392    return general_names
393
394
395def _encode_subject_key_identifier(backend, ski):
396    return _encode_asn1_str_gc(backend, ski.digest)
397
398
399def _encode_general_name(backend, name):
400    gn = backend._lib.GENERAL_NAME_new()
401    _encode_general_name_preallocated(backend, name, gn)
402    return gn
403
404
405def _encode_general_name_preallocated(backend, name, gn):
406    if isinstance(name, x509.DNSName):
407        backend.openssl_assert(gn != backend._ffi.NULL)
408        gn.type = backend._lib.GEN_DNS
409
410        ia5 = backend._lib.ASN1_IA5STRING_new()
411        backend.openssl_assert(ia5 != backend._ffi.NULL)
412        # ia5strings are supposed to be ITU T.50 but to allow round-tripping
413        # of broken certs that encode utf8 we'll encode utf8 here too.
414        value = name.value.encode("utf8")
415
416        res = backend._lib.ASN1_STRING_set(ia5, value, len(value))
417        backend.openssl_assert(res == 1)
418        gn.d.dNSName = ia5
419    elif isinstance(name, x509.RegisteredID):
420        backend.openssl_assert(gn != backend._ffi.NULL)
421        gn.type = backend._lib.GEN_RID
422        obj = backend._lib.OBJ_txt2obj(
423            name.value.dotted_string.encode("ascii"), 1
424        )
425        backend.openssl_assert(obj != backend._ffi.NULL)
426        gn.d.registeredID = obj
427    elif isinstance(name, x509.DirectoryName):
428        backend.openssl_assert(gn != backend._ffi.NULL)
429        dir_name = _encode_name(backend, name.value)
430        gn.type = backend._lib.GEN_DIRNAME
431        gn.d.directoryName = dir_name
432    elif isinstance(name, x509.IPAddress):
433        backend.openssl_assert(gn != backend._ffi.NULL)
434        if isinstance(name.value, ipaddress.IPv4Network):
435            packed = name.value.network_address.packed + utils.int_to_bytes(
436                ((1 << 32) - name.value.num_addresses), 4
437            )
438        elif isinstance(name.value, ipaddress.IPv6Network):
439            packed = name.value.network_address.packed + utils.int_to_bytes(
440                (1 << 128) - name.value.num_addresses, 16
441            )
442        else:
443            packed = name.value.packed
444        ipaddr = _encode_asn1_str(backend, packed)
445        gn.type = backend._lib.GEN_IPADD
446        gn.d.iPAddress = ipaddr
447    elif isinstance(name, x509.OtherName):
448        backend.openssl_assert(gn != backend._ffi.NULL)
449        other_name = backend._lib.OTHERNAME_new()
450        backend.openssl_assert(other_name != backend._ffi.NULL)
451
452        type_id = backend._lib.OBJ_txt2obj(
453            name.type_id.dotted_string.encode("ascii"), 1
454        )
455        backend.openssl_assert(type_id != backend._ffi.NULL)
456        data = backend._ffi.new("unsigned char[]", name.value)
457        data_ptr_ptr = backend._ffi.new("unsigned char **")
458        data_ptr_ptr[0] = data
459        value = backend._lib.d2i_ASN1_TYPE(
460            backend._ffi.NULL, data_ptr_ptr, len(name.value)
461        )
462        if value == backend._ffi.NULL:
463            backend._consume_errors()
464            raise ValueError("Invalid ASN.1 data")
465        other_name.type_id = type_id
466        other_name.value = value
467        gn.type = backend._lib.GEN_OTHERNAME
468        gn.d.otherName = other_name
469    elif isinstance(name, x509.RFC822Name):
470        backend.openssl_assert(gn != backend._ffi.NULL)
471        # ia5strings are supposed to be ITU T.50 but to allow round-tripping
472        # of broken certs that encode utf8 we'll encode utf8 here too.
473        data = name.value.encode("utf8")
474        asn1_str = _encode_asn1_str(backend, data)
475        gn.type = backend._lib.GEN_EMAIL
476        gn.d.rfc822Name = asn1_str
477    elif isinstance(name, x509.UniformResourceIdentifier):
478        backend.openssl_assert(gn != backend._ffi.NULL)
479        # ia5strings are supposed to be ITU T.50 but to allow round-tripping
480        # of broken certs that encode utf8 we'll encode utf8 here too.
481        data = name.value.encode("utf8")
482        asn1_str = _encode_asn1_str(backend, data)
483        gn.type = backend._lib.GEN_URI
484        gn.d.uniformResourceIdentifier = asn1_str
485    else:
486        raise ValueError("{} is an unknown GeneralName type".format(name))
487
488
489def _encode_extended_key_usage(backend, extended_key_usage):
490    eku = backend._lib.sk_ASN1_OBJECT_new_null()
491    eku = backend._ffi.gc(eku, backend._lib.sk_ASN1_OBJECT_free)
492    for oid in extended_key_usage:
493        obj = _txt2obj(backend, oid.dotted_string)
494        res = backend._lib.sk_ASN1_OBJECT_push(eku, obj)
495        backend.openssl_assert(res >= 1)
496
497    return eku
498
499
500_CRLREASONFLAGS = {
501    x509.ReasonFlags.key_compromise: 1,
502    x509.ReasonFlags.ca_compromise: 2,
503    x509.ReasonFlags.affiliation_changed: 3,
504    x509.ReasonFlags.superseded: 4,
505    x509.ReasonFlags.cessation_of_operation: 5,
506    x509.ReasonFlags.certificate_hold: 6,
507    x509.ReasonFlags.privilege_withdrawn: 7,
508    x509.ReasonFlags.aa_compromise: 8,
509}
510
511
512def _encode_reasonflags(backend, reasons):
513    bitmask = backend._lib.ASN1_BIT_STRING_new()
514    backend.openssl_assert(bitmask != backend._ffi.NULL)
515    for reason in reasons:
516        res = backend._lib.ASN1_BIT_STRING_set_bit(
517            bitmask, _CRLREASONFLAGS[reason], 1
518        )
519        backend.openssl_assert(res == 1)
520
521    return bitmask
522
523
524def _encode_full_name(backend, full_name):
525    dpn = backend._lib.DIST_POINT_NAME_new()
526    backend.openssl_assert(dpn != backend._ffi.NULL)
527    dpn.type = _DISTPOINT_TYPE_FULLNAME
528    dpn.name.fullname = _encode_general_names(backend, full_name)
529    return dpn
530
531
532def _encode_relative_name(backend, relative_name):
533    dpn = backend._lib.DIST_POINT_NAME_new()
534    backend.openssl_assert(dpn != backend._ffi.NULL)
535    dpn.type = _DISTPOINT_TYPE_RELATIVENAME
536    dpn.name.relativename = _encode_sk_name_entry(backend, relative_name)
537    return dpn
538
539
540def _encode_cdps_freshest_crl(backend, cdps):
541    cdp = backend._lib.sk_DIST_POINT_new_null()
542    cdp = backend._ffi.gc(cdp, backend._lib.sk_DIST_POINT_free)
543    for point in cdps:
544        dp = backend._lib.DIST_POINT_new()
545        backend.openssl_assert(dp != backend._ffi.NULL)
546
547        if point.reasons:
548            dp.reasons = _encode_reasonflags(backend, point.reasons)
549
550        if point.full_name:
551            dp.distpoint = _encode_full_name(backend, point.full_name)
552
553        if point.relative_name:
554            dp.distpoint = _encode_relative_name(backend, point.relative_name)
555
556        if point.crl_issuer:
557            dp.CRLissuer = _encode_general_names(backend, point.crl_issuer)
558
559        res = backend._lib.sk_DIST_POINT_push(cdp, dp)
560        backend.openssl_assert(res >= 1)
561
562    return cdp
563
564
565def _encode_name_constraints(backend, name_constraints):
566    nc = backend._lib.NAME_CONSTRAINTS_new()
567    backend.openssl_assert(nc != backend._ffi.NULL)
568    nc = backend._ffi.gc(nc, backend._lib.NAME_CONSTRAINTS_free)
569    permitted = _encode_general_subtree(
570        backend, name_constraints.permitted_subtrees
571    )
572    nc.permittedSubtrees = permitted
573    excluded = _encode_general_subtree(
574        backend, name_constraints.excluded_subtrees
575    )
576    nc.excludedSubtrees = excluded
577
578    return nc
579
580
581def _encode_policy_constraints(backend, policy_constraints):
582    pc = backend._lib.POLICY_CONSTRAINTS_new()
583    backend.openssl_assert(pc != backend._ffi.NULL)
584    pc = backend._ffi.gc(pc, backend._lib.POLICY_CONSTRAINTS_free)
585    if policy_constraints.require_explicit_policy is not None:
586        pc.requireExplicitPolicy = _encode_asn1_int(
587            backend, policy_constraints.require_explicit_policy
588        )
589
590    if policy_constraints.inhibit_policy_mapping is not None:
591        pc.inhibitPolicyMapping = _encode_asn1_int(
592            backend, policy_constraints.inhibit_policy_mapping
593        )
594
595    return pc
596
597
598def _encode_general_subtree(backend, subtrees):
599    if subtrees is None:
600        return backend._ffi.NULL
601    else:
602        general_subtrees = backend._lib.sk_GENERAL_SUBTREE_new_null()
603        for name in subtrees:
604            gs = backend._lib.GENERAL_SUBTREE_new()
605            gs.base = _encode_general_name(backend, name)
606            res = backend._lib.sk_GENERAL_SUBTREE_push(general_subtrees, gs)
607            backend.openssl_assert(res >= 1)
608
609        return general_subtrees
610
611
612def _encode_precert_signed_certificate_timestamps(backend, scts):
613    sct_stack = backend._lib.sk_SCT_new_null()
614    backend.openssl_assert(sct_stack != backend._ffi.NULL)
615    sct_stack = backend._ffi.gc(sct_stack, backend._lib.sk_SCT_free)
616    for sct in scts:
617        res = backend._lib.sk_SCT_push(sct_stack, sct._sct)
618        backend.openssl_assert(res >= 1)
619    return sct_stack
620
621
622def _encode_nonce(backend, nonce):
623    return _encode_asn1_str_gc(backend, nonce.nonce)
624
625
626_EXTENSION_ENCODE_HANDLERS = {
627    ExtensionOID.BASIC_CONSTRAINTS: _encode_basic_constraints,
628    ExtensionOID.SUBJECT_KEY_IDENTIFIER: _encode_subject_key_identifier,
629    ExtensionOID.KEY_USAGE: _encode_key_usage,
630    ExtensionOID.SUBJECT_ALTERNATIVE_NAME: _encode_alt_name,
631    ExtensionOID.ISSUER_ALTERNATIVE_NAME: _encode_alt_name,
632    ExtensionOID.EXTENDED_KEY_USAGE: _encode_extended_key_usage,
633    ExtensionOID.AUTHORITY_KEY_IDENTIFIER: _encode_authority_key_identifier,
634    ExtensionOID.CERTIFICATE_POLICIES: _encode_certificate_policies,
635    ExtensionOID.AUTHORITY_INFORMATION_ACCESS: _encode_information_access,
636    ExtensionOID.SUBJECT_INFORMATION_ACCESS: _encode_information_access,
637    ExtensionOID.CRL_DISTRIBUTION_POINTS: _encode_cdps_freshest_crl,
638    ExtensionOID.FRESHEST_CRL: _encode_cdps_freshest_crl,
639    ExtensionOID.INHIBIT_ANY_POLICY: _encode_inhibit_any_policy,
640    ExtensionOID.OCSP_NO_CHECK: _encode_ocsp_nocheck,
641    ExtensionOID.NAME_CONSTRAINTS: _encode_name_constraints,
642    ExtensionOID.POLICY_CONSTRAINTS: _encode_policy_constraints,
643    ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS: (
644        _encode_precert_signed_certificate_timestamps
645    ),
646}
647
648_CRL_EXTENSION_ENCODE_HANDLERS = {
649    ExtensionOID.ISSUER_ALTERNATIVE_NAME: _encode_alt_name,
650    ExtensionOID.AUTHORITY_KEY_IDENTIFIER: _encode_authority_key_identifier,
651    ExtensionOID.AUTHORITY_INFORMATION_ACCESS: _encode_information_access,
652    ExtensionOID.CRL_NUMBER: _encode_crl_number_delta_crl_indicator,
653    ExtensionOID.DELTA_CRL_INDICATOR: _encode_crl_number_delta_crl_indicator,
654    ExtensionOID.ISSUING_DISTRIBUTION_POINT: _encode_issuing_dist_point,
655    ExtensionOID.FRESHEST_CRL: _encode_cdps_freshest_crl,
656}
657
658_CRL_ENTRY_EXTENSION_ENCODE_HANDLERS = {
659    CRLEntryExtensionOID.CERTIFICATE_ISSUER: _encode_alt_name,
660    CRLEntryExtensionOID.CRL_REASON: _encode_crl_reason,
661    CRLEntryExtensionOID.INVALIDITY_DATE: _encode_invalidity_date,
662}
663
664_OCSP_REQUEST_EXTENSION_ENCODE_HANDLERS = {
665    OCSPExtensionOID.NONCE: _encode_nonce,
666}
667
668_OCSP_BASICRESP_EXTENSION_ENCODE_HANDLERS = {
669    OCSPExtensionOID.NONCE: _encode_nonce,
670}
671