-
Notifications
You must be signed in to change notification settings - Fork 33
/
x509.mli
816 lines (660 loc) · 32.6 KB
/
x509.mli
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
(** X509 encoding, generation, and validation.
[X509] is a module for handling X.509 certificates, as described in
{{:https://tools.ietf.org/html/rfc5280}RFC 5280}. X.509 describes a
hierarchical public key infrastructure, where all trust is delegated to
certificate authorities (CA). The task of a CA is to sign certificate
signing requests (CSR), which turns them into certificates, after
verification that the requestor is eligible.
An X.509 certificate is an authentication token: a public key, a subject
(e.g. server name), a validity period, optionally a purpose (usage), and
various other optional {{!Extension}Extensions}.
The public keys of trusted CAs are distributed with the software, or
configured manually. When an endpoint connects, it has to present its
certificate chain, which are pairwise signed certificates. This chain is
verified: the signatures have to be valid, the last certificate must be
signed by a trusted CA, the name has to match the expected name, all
certificates must be valid at the current time, and the purpose of each
certificate must match its usage. An alternative validator checks that the
hash of the server certificate matches the given hash.
This module provides {{!Encoding}parsers and unparsers} (PEM encoding) of
ASN.1 encoded X.509 certificates, public and private RSA keys
({{:http://tools.ietf.org/html/rfc5208}PKCS 8, RFC 5208}), and certificate
signing requests ({{:http://tools.ietf.org/html/rfc2986}PKCS 10, RFC 2986})
(both require parts of {{:https://tools.ietf.org/html/rfc2985}PKCS9, RFC
2985}), {{!Validation} validation} of certificates, and construction of
{{!Authenticator} authenticators}. Name validation, as defined in
{{:https://tools.ietf.org/html/rfc6125}RFC 6125}, is also implemented. The
{{!CA}CA} module provides functionality to create and sign CSR.
Missing is the handling of online certificate status protocol. Some X.509v3
extensions are not handled, but only parsed, such as name constraints. If any
extension is marked as critical in a certificate, but not handled, the
validation will fail. The only supported key type is RSA.
{e %%VERSION%% - {{:%%PKG_HOMEPAGE%% }homepage}} *)
(** {1 Abstract certificate type} *)
(** The abstract type of a certificate, with
{{!Encoding.Pem.Certificate}encoding and decoding to PEM}. *)
type t
(** [pp ppf cert] pretty-prints the certificate. *)
val pp : t Fmt.t
(** {1 Basic operations on a certificate} *)
(** The polymorphic variant of public key types. *)
type key_type = [ `RSA | `EC of Asn.oid ]
(** [supports_keytype certificate key_type] is [result], whether public key of
the [certificate] matches the given [key_type]. *)
val supports_keytype : t -> key_type -> bool
(** The polymorphic variant of public keys, with
{{:http://tools.ietf.org/html/rfc5208}PKCS 8}
{{!Encoding.Pem.Public_key}encoding and decoding to PEM}. *)
type public_key = [ `RSA of Nocrypto.Rsa.pub | `EC_pub of Asn.oid ]
(** [key_id public_key] is [result], the 160-bit [`SHA1] hash of the BIT
STRING subjectPublicKey (excluding tag, length, and number of
unused bits) for publicKeyInfo of [public_key].
{{:https://tools.ietf.org/html/rfc5280#section-4.2.1.2}RFC 5280, 4.2.1.2, variant (1)} *)
val key_id: public_key -> Cstruct.t
(** [key_fingerprint ?hash public_key] is [result], the hash (by
default SHA256) of the DER encoded public key (equivalent to
[openssl x509 -noout -pubkey | openssl pkey -pubin -outform DER | openssl dgst -HASH]). *)
val key_fingerprint : ?hash:Nocrypto.Hash.hash -> public_key -> Cstruct.t
(** The polymorphic variant of private keys, with
{{:http://tools.ietf.org/html/rfc5208}PKCS 8}
{{!Encoding.Pem.Private_key}encoding and decoding to PEM}. *)
type private_key = [ `RSA of Nocrypto.Rsa.priv ]
(** [public_key certificate] is [pk], the public key of the [certificate]. *)
val public_key : t -> public_key
(** [hostnames certficate] are [hostnames], the list of hostnames this
[certificate] is valid for. Currently, these are the DNS names of the
{{:https://tools.ietf.org/html/rfc5280#section-4.2.1.6}Subject Alternative Name}
extension, if present, or otherwise the singleton list containing the common
name. *)
val hostnames : t -> string list
(** The polymorphic variant for hostname validation. *)
type host = [ `Strict of string | `Wildcard of string ]
(** [supports_hostname certificate host] is [result], whether the [certificate]
contains the given [host], using {!hostnames}. *)
val supports_hostname : t -> host -> bool
(** The polymorphic variant of a distinguished name component, as defined in
X.500. *)
type component = [
| `CN of string
| `Serialnumber of string
| `C of string
| `L of string
| `SP of string
| `O of string
| `OU of string
| `T of string
| `DNQ of string
| `Mail of string
| `DC of string
| `Given_name of string
| `Surname of string
| `Initials of string
| `Pseudonym of string
| `Generation of string
| `Other of Asn.oid * string
]
(** A distinguished name is a list of {!component}. *)
type distinguished_name = component list
(** [pp_distinguished_name ppf dn] pretty-prints the distinguished name. *)
val pp_distinguished_name : distinguished_name Fmt.t
(** [fingerprint hash cert] is [digest], the digest of [cert] using the
specified [hash] algorithm *)
val fingerprint : Nocrypto.Hash.hash -> t -> Cstruct.t
(** [subject certificate] is [dn], the subject as {{!distinguished_name}dn} of
the [certificate]. *)
val subject : t -> distinguished_name
(** [issuer certificate] is [dn], the issuer as {{!distinguished_name}dn} of
the [certificate]. *)
val issuer : t -> distinguished_name
(** [serial certificate] is [sn], the serial number of the [certificate]. *)
val serial : t -> Z.t
(** [validity certificate] is [from, until], the validity of the certificate. *)
val validity : t -> Ptime.t * Ptime.t
(** X.509v3 extensions *)
module Extension : sig
(** {1 X.509v3 extension} *)
(** The polymorphic variant of
{{:https://tools.ietf.org/html/rfc5280#section-4.2.1.3}key usages}. *)
type key_usage = [
| `Digital_signature
| `Content_commitment
| `Key_encipherment
| `Data_encipherment
| `Key_agreement
| `Key_cert_sign
| `CRL_sign
| `Encipher_only
| `Decipher_only
]
(** [supports_usage ~not_present certificate key_usage] is [result],
whether the [certificate] supports the given [key_usage]
(defaults to [~not_present] if the certificate does not contain
a keyUsage extension). *)
val supports_usage : ?not_present:bool -> t -> key_usage -> bool
(** The polymorphic variant of
{{:https://tools.ietf.org/html/rfc5280#section-4.2.1.12}extended key usages}. *)
type extended_key_usage = [
| `Any
| `Server_auth
| `Client_auth
| `Code_signing
| `Email_protection
| `Ipsec_end
| `Ipsec_tunnel
| `Ipsec_user
| `Time_stamping
| `Ocsp_signing
| `Other of Asn.oid
]
(** [supports_extended_usage ~not_present certificate extended_key_usage] is
[result], whether the [certificate] supports the requested
[extended_key_usage] (defaults to [~not_present] if the certificate does
not contain an extendedKeyUsage extension. *)
val supports_extended_usage : ?not_present:bool -> t -> extended_key_usage -> bool
(** [basic_constraints cert] extracts the BasicConstraints extension, if
present. *)
val basic_constraints : t -> (bool * int option) option
(** A list of [general_name]s is the value of both
{{:https://tools.ietf.org/html/rfc5280#section-4.2.1.6}subjectAltName}
and
{{:https://tools.ietf.org/html/rfc5280#section-4.2.1.7}IssuerAltName}
extension. *)
type general_name = [
| `Other of (Asn.oid * string)
| `Rfc_822 of string
| `DNS of string
| `X400_address of unit
| `Directory of distinguished_name
| `EDI_party of (string option * string)
| `URI of string
| `IP of Cstruct.t
| `Registered_id of Asn.oid
]
(** The authority key identifier, as present in the
{{:https://tools.ietf.org/html/rfc5280#section-4.2.1.1}Authority Key Identifier}
extension. *)
type authority_key_id = Cstruct.t option * general_name list * Z.t option
(** The private key usage period, as defined in
{{:https://tools.ietf.org/html/rfc3280#section-4.2.1.4}RFC 3280}. *)
type priv_key_usage_period = [
| `Interval of Ptime.t * Ptime.t
| `Not_after of Ptime.t
| `Not_before of Ptime.t
]
(** Name constraints, as defined in
{{:https://tools.ietf.org/html/rfc5280#section-4.2.1.10}RFC 5280}. *)
type name_constraint = (general_name * int * int option) list
(** Certificate policies, the
{{:https://tools.ietf.org/html/rfc5280#section-4.2.1.4}policy extension}. *)
type policy = [ `Any | `Something of Asn.oid ]
(** [unsupported cert oid] is [None] if [oid] is not present as extension, or
[Some (crit, data)] if an extension with [oid] is present. *)
val unsupported : t -> Asn.OID.t -> (bool * Cstruct.t) option
(** Returns [subject_alt_names] if extension if present, else [ [] ]. *)
val subject_alt_names : t -> general_name list
(** Type of allowed revocation reasons for a given distribution point. *)
type reason = [
| `Unused
| `Key_compromise
| `CA_compromise
| `Affiliation_changed
| `Superseded
| `Cessation_of_operation
| `Certificate_hold
| `Privilege_withdrawn
| `AA_compromise
]
(** Distribution point name, either a full one using general names, or a
relative one using a distinguished name. *)
type distribution_point_name =
[ `Full of general_name list
| `Relative of distinguished_name ]
(** Distribution point, consisting of an optional name, an optional list of
allowed reasons, and an optional issuer. *)
type distribution_point =
distribution_point_name option *
reason list option *
distinguished_name option
(** Returns [crl_distribution_points] if extension if present, else [ [] ]. *)
val crl_distribution_points : t -> distribution_point list
(** The reason of a revoked certificate. *)
type reason_code = [
| `Unspecified
| `Key_compromise
| `CA_compromise
| `Affiliation_changed
| `Superseded
| `Cessation_of_operation
| `Certificate_hold
| `Remove_from_CRL
| `Privilege_withdrawn
| `AA_compromise
]
(** The polymorphic variant of
{{:https://tools.ietf.org/html/rfc5280#section-4.2}X509v3 extensions}. *)
type t = [
| `Unsupported of Asn.oid * Cstruct.t
| `Subject_alt_name of general_name list
| `Authority_key_id of authority_key_id
| `Subject_key_id of Cstruct.t
| `Issuer_alt_name of general_name list
| `Key_usage of key_usage list
| `Ext_key_usage of extended_key_usage list
| `Basic_constraints of (bool * int option)
| `CRL_number of int
| `Delta_CRL_indicator of int
| `Priv_key_period of priv_key_usage_period
| `Name_constraints of name_constraint * name_constraint
| `CRL_distribution_points of distribution_point list
| `Issuing_distribution_point of distribution_point_name option * bool * bool * reason list option * bool * bool
| `Freshest_CRL of distribution_point list
| `Reason of reason_code
| `Invalidity_date of Ptime.t
| `Certificate_issuer of general_name list
| `Policies of policy list
]
end
(** Certificate Authority operations *)
module CA : sig
(** {1 Signing} *)
(** The abstract type of a (self-signed)
{{:https://tools.ietf.org/html/rfc2986#page-7}PKCS 10 certification request},
with {{!Encoding.Pem.Certificate_signing_request}encoding and decoding to PEM}. *)
type signing_request
(** The polymorphic variant of certificate request extensions, as defined in
{{:http://tools.ietf.org/html/rfc2985}PKCS 9 (RFC 2985)}. *)
type request_extensions = [
| `Password of string
| `Name of string
| `Extensions of (bool * Extension.t) list
]
(** The raw request info of a
{{:https://tools.ietf.org/html/rfc2986#section-4}PKCS 10 certification request info}. *)
type request_info = {
subject : distinguished_name ;
public_key : public_key ;
extensions : request_extensions list ;
}
(** [info signing_request] is {!request_info}, the information inside the
{!signing_request}. *)
val info : signing_request -> request_info
(** [request subject ~digest ~extensions private] creates [signing_request],
a certification request using the given [subject], [digest] (defaults to
[`SHA256]) and list of [extensions]. *)
val request : distinguished_name -> ?digest:Nocrypto.Hash.hash -> ?extensions:request_extensions list -> private_key -> signing_request
(** [sign signing_request ~digest ~valid_from ~valid_until ~serial ~extensions private issuer]
creates [certificate], a signed certificate. Public key and subject are
taken from the [signing_request], the [extensions] are added to the X.509
certificate. The [private] key is used to sign the certificate, the
[issuer] is recorded in the certificate. The digest defaults to
[`SHA256]. The [serial] defaults to a random value between 1 and 2^64.
Certificate version is always 3. Please note that the extensions in the
[signing_request] are ignored, you can pass them using:
{[match
try Some (List.find (function `Extensions _ -> true | _ -> false) (info csr).extensions)
with Not_found -> None
with
| Some (`Extensions x) -> x
| None -> []
]} *)
val sign : signing_request -> valid_from:Ptime.t -> valid_until:Ptime.t -> ?digest:Nocrypto.Hash.hash -> ?serial:Z.t -> ?extensions:(bool * Extension.t) list -> private_key -> distinguished_name -> t
end
(** X.509 Certificate Revocation Lists. *)
module CRL : sig
(** A certificate revocation list is a signed structure consisting of an
issuer, a timestamp, possibly a timestamp when to expect the next update,
and a list of revoked certificates (represented by a serial, a revocation
date, and extensions (e.g. reason) - see RFC 5280 section 5.2 for a list
of available extensions (not enforced)). It also may contain any
extensions, e.g. a CRL number and whether it is partial or complete. *)
(** The type of a revocation list, kept abstract. *)
type c
(** [issuer c] is the issuer of the revocation list. *)
val issuer : c -> distinguished_name
(** [this_update t] is the timestamp of the revocation list. *)
val this_update : c -> Ptime.t
(** [next_update t] is either [None] or [Some ts], the timestamp of the next
update. *)
val next_update : c -> Ptime.t option
(** The type of a revoked certificate, which consists of a serial number, the
revocation date, and possibly extensions. See RFC 5280 setion 5.3 for
allowed extensions (not enforced). *)
type revoked_cert = {
serial : Z.t ;
date : Ptime.t ;
extensions : (bool * Extension.t) list
}
(** [reason revoked] extracts the [Reason] extension from [revoked] if
present. *)
val reason : revoked_cert -> Extension.reason_code option
(** [revoked_certificates t] is the list of revoked certificates of the
revocation list. *)
val revoked_certificates : c -> revoked_cert list
(** [extensions t] is the list of extensions, see RFC 5280 section 5.2 for
possible values. *)
val extensions : c -> (bool * Extension.t) list
(** [crl_number t] is the number of the CRL. *)
val crl_number : c -> int option
(** [validate t pk] validates the digital signature of the revocation list. *)
val validate : c -> public_key -> bool
(** [verify t ~time cert] verifies that the issuer of [t] matches the subject
of [cert], and validates the digital signature of the revocation list. If
[time] is provided, it must be after [this_update] and before
[next_update] of [t]. *)
val verify : c -> ?time:Ptime.t -> t -> bool
(** [is_revoked crls ~issuer ~cert] is [true] if there exists a revocation of
[cert] in [crls] which is signed by the [issuer]. The subject of [issuer]
must match the issuer of the crl. *)
val is_revoked : c list -> issuer:t -> cert:t -> bool
(** [revoked ~digest ~issuer ~this_update ~next_update ~extensions certs priv]
constructs a revocation list with the given parameters. *)
val revoke : ?digest:Nocrypto.Hash.hash ->
issuer:distinguished_name ->
this_update:Ptime.t -> ?next_update:Ptime.t ->
?extensions:(bool * Extension.t) list ->
revoked_cert list -> private_key -> c
(** [revoke_certificate cert ~this_update ~next_update t priv] adds [cert] to
the revocation list, increments its counter, adjusts [this_update] and
[next_update] timestamps, and digitally signs it using [priv]. *)
val revoke_certificate : revoked_cert ->
this_update:Ptime.t -> ?next_update:Ptime.t -> c -> private_key -> c
(** [revoke_certificates certs ~this_update ~next_update t priv] adds [certs]
to the revocation list, increments its counter, adjusts [this_update] and
[next_update] timestamps, and digitally signs it using [priv]. *)
val revoke_certificates : revoked_cert list ->
this_update:Ptime.t -> ?next_update:Ptime.t -> c -> private_key -> c
end
(** X.509 Certificate Chain Validation. *)
module Validation : sig
(** A chain of pairwise signed X.509 certificates is sent to the endpoint,
which use these to authenticate the other endpoint. Usually a set of
trust anchors is configured on the endpoint, and the chain needs to be
rooted in one of the trust anchors. In reality, chains may be incomplete
or reversed, and there can be multiple paths from the leaf certificate to
a trust anchor.
RFC 5280 specifies a {{:https://tools.ietf.org/html/rfc5280#section-6}path
validation} algorithm for authenticating chains, but this does not handle
multiple possible paths. {{:https://tools.ietf.org/html/rfc4158}RFC 4158}
describes possible path building strategies.
This module provides path building, chain of trust verification, trust
anchor (certificate authority) validation, and validation via a
fingerprint list (for a trust on first use implementation).
*)
(** {2 Certificate Authorities} *)
(** The polymorphic variant of possible certificate authorities failures. *)
type ca_error = [
| `CAIssuerSubjectMismatch of t
| `CAInvalidVersion of t
| `CAInvalidSelfSignature of t
| `CACertificateExpired of t * Ptime.t option
| `CAInvalidExtensions of t
]
(** [pp_ca_error ppf ca_error] pretty-prints the CA error [ca_error]. *)
val pp_ca_error : ca_error Fmt.t
(** [valid_ca ~time certificate] is [result], which is [Ok ()] if the given
certificate is self-signed, it is valid at [time], its extensions are not
present (if X.509 version 1 certificate), or are appropriate for a CA
(BasicConstraints is present and true, KeyUsage extension contains
keyCertSign). *)
val valid_ca : ?time:Ptime.t -> t -> (unit, ca_error) result
(** [valid_cas ~time certificates] is [valid_certificates], only those
certificates which pass the {!valid_ca} check. *)
val valid_cas : ?time:Ptime.t -> t list -> t list
(** {2 Chain of trust verification} *)
(** The polymorphic variant of a leaf certificate validation error. *)
type leaf_validation_error = [
| `LeafCertificateExpired of t * Ptime.t option
| `LeafInvalidName of t * host option
| `LeafInvalidVersion of t
| `LeafInvalidExtensions of t
]
(** The polymorphic variant of a chain validation error. *)
type chain_validation_error = [
| `IntermediateInvalidExtensions of t
| `IntermediateCertificateExpired of t * Ptime.t option
| `IntermediateInvalidVersion of t
| `ChainIssuerSubjectMismatch of t * t
| `ChainAuthorityKeyIdSubjectKeyIdMismatch of t * t
| `ChainInvalidSignature of t * t
| `ChainInvalidPathlen of t * int
| `EmptyCertificateChain
| `NoTrustAnchor of t
| `Revoked of t
]
(** [build_paths server rest] is [paths], which are all possible certificate
paths starting with [server]. These chains (C1..Cn) fulfill the predicate
that each certificate Cn is issued by the next one in the chain (C(n+1)):
the issuer of Cn matches the subject of C(n+1). This is as described in
{{:https://tools.ietf.org/html/rfc4158}RFC 4158}. *)
val build_paths : t -> t list -> t list list
(** The polymorphic variant of a chain validation error: either the leaf
certificate is problematic, or the chain itself. *)
type chain_error = [
| `Leaf of leaf_validation_error
| `Chain of chain_validation_error
]
(** [pp_chain_error ppf chain_error] pretty-prints the [chain_error]. *)
val pp_chain_error : chain_error Fmt.t
(** [verify_chain ~host ~time ~revoked ~anchors chain] is [result], either
[Ok] and the trust anchor used to verify the chain, or [Error] and the
chain error. RFC 5280 describes the implemented
{{:https://tools.ietf.org/html/rfc5280#section-6.1}path validation}
algorithm: The validity period of the given certificates is checked
against the [time]. The X509v3 extensions of the [chain] are checked,
then a chain of trust from [anchors] to the server certificate is
validated. The path length constraints are checked. The server
certificate is checked to contain the given [host], using {!hostnames}.
The returned certificate is the root of the chain, a member of the given
list of [anchors]. *)
val verify_chain : ?host:host -> ?time:Ptime.t ->
?revoked:(issuer:t -> cert:t -> bool) ->
anchors:(t list) -> t list -> (t, chain_error) result
(** The polymorphic variant of a fingerprint validation error. *)
type fingerprint_validation_error = [
| `ServerNameNotPresent of t * string
| `NameNotInList of t
| `InvalidFingerprint of t * Cstruct.t * Cstruct.t
]
(** The polymorphic variant of validation errors. *)
type validation_error = [
| `EmptyCertificateChain
| `InvalidChain
| `Leaf of leaf_validation_error
| `Fingerprint of fingerprint_validation_error
]
(** [pp_validation_error ppf validation_error] pretty-prints the
[validation_error]. *)
val pp_validation_error : validation_error Fmt.t
(** [verify_chain_of_trust ~host ~time ~revoked ~anchors certificates] is
[result]. First, all possible paths are constructed using the
{!build_paths} function, the first certificate of the chain is verified to
be a valid leaf certificate (no BasicConstraints extension) and contains
the given [host] (using {!hostnames}); if some path is valid, using
{!verify_chain}, the result will be [Ok] and contain the actual
certificate chain and the trust anchor. *)
val verify_chain_of_trust :
?host:host -> ?time:Ptime.t -> ?revoked:(issuer:t -> cert:t -> bool) ->
anchors:(t list) -> t list -> ((t list * t) option, validation_error) result
(** {2 Fingerprint verification} *)
(** [trust_key_fingerprint ~time ~hash ~fingerprints certificates] is
[result], the first element of [certificates] is verified against the
given [fingerprints] map (hostname to public key fingerprint) using
{!key_fingerprint}. The certificate has to be valid in the given [time].
If a [host] is provided, the certificate is checked for this name. The
[`Wildcard hostname] of the fingerprint list must match the name in the
certificate, using {!hostnames}. *)
val trust_key_fingerprint :
?host:host -> ?time:Ptime.t -> hash:Nocrypto.Hash.hash ->
fingerprints:(string * Cstruct.t) list -> t list ->
((t list * t) option, validation_error) result
(** [trust_cert_fingerprint ~time ~hash ~fingerprints certificates] is
[result], the first element of [certificates] is verified to match the
given [fingerprints] map (hostname to fingerprint) using {!fingerprint}.
The certificate has to be valid in the given [time]. If a [host] is
provided, the certificate is checked for this name. The
[`Wildcard hostname] of the fingerprint list must match the name in the
certificate, using {!hostnames}. *)
val trust_cert_fingerprint :
?host:host -> ?time:Ptime.t -> hash:Nocrypto.Hash.hash ->
fingerprints:(string * Cstruct.t) list -> t list ->
((t list * t) option, validation_error) result
[@@ocaml.deprecated "Pin public keys (use trust_key_fingerprint) instead of certificates."]
end
(** Authenticators of certificate chains *)
module Authenticator : sig
(** {1 Authenticators} *)
(** An authenticator [a] is a function type which takes a hostname and a
certificate stack to an authentication decision {!Validation.result}. *)
type a = ?host:host -> t list ->
((t list * t) option, Validation.validation_error) result
(** [chain_of_trust ?time trust_anchors] is [authenticator], which uses the
given [time] and list of [trust_anchors] to verify the certificate chain.
This is an implementation of the algorithm described in
{{:https://tools.ietf.org/html/rfc5280#section-6.1}RFC 5280}, using
{!Validation.verify_chain_of_trust}. The given trust anchors are not
checked to be valid trust anchors any further (you have to do this
manually with {!Validation.valid_ca} or {!Validation.valid_cas})! *)
val chain_of_trust : ?time:Ptime.t -> ?crls:CRL.c list -> t list -> a
(** [server_key_fingerprint ~time hash fingerprints] is an [authenticator]
that uses the given [time] and list of [fingerprints] to verify that the
fingerprint of the first element of the certificate chain matches the
given fingerprint, using {!Validation.trust_key_fingerprint}. *)
val server_key_fingerprint : ?time:Ptime.t -> hash:Nocrypto.Hash.hash ->
fingerprints:(string * Cstruct.t) list -> a
(** [server_cert_fingerprint ~time hash fingerprints] is an [authenticator]
that uses the given [time] and list of [fingerprints] to verify the first
element of the certificate chain, using
{!Validation.trust_cert_fingerprint}. *)
val server_cert_fingerprint : ?time:Ptime.t -> hash:Nocrypto.Hash.hash ->
fingerprints:(string * Cstruct.t) list -> a
[@@ocaml.deprecated "Pin public keys (use server_key_fingerprint) instead of certificates."]
(** [null] is [authenticator], which always returns [Ok ()]. (Useful for
testing purposes only.) *)
val null : a
end
(** Encodings *)
module Encoding : sig
(** The typ for decoding errors. *)
type err = Asn.error
(** [pp_err ppf err] pretty-prints the error. *)
val pp_err : err Fmt.t
(** {1 ASN.1 Encoding} *)
(** [parse cstruct] is [certificate option], the ASN.1 decoded [certificate]
or an error. *)
val parse : Cstruct.t -> (t, err) result
(** [cs_of_cert certificate] is [cstruct], the ASN.1 encoded representation of
the [certificate]. *)
val cs_of_cert : t -> Cstruct.t
(** [distinguished_name_of_cs cs] is [dn], the ASN.1 decoded distinguished
name of [cs]. *)
val distinguished_name_of_cs : Cstruct.t -> (distinguished_name, err) result
(** [cs_of_distinguished_name dn] is [cstruct], the ASN.1 encoded
representation of the distinguished name [dn]. *)
val cs_of_distinguished_name : distinguished_name -> Cstruct.t
(** [parse_signing_request cstruct] is [signing_request], the ASN.1 decoded
[cstruct] or an error. *)
val parse_signing_request : Cstruct.t -> (CA.signing_request, err) result
(** [cs_of_signing_request sr] is [cstruct], the ASN.1 encoded representation
of the [sr]. *)
val cs_of_signing_request : CA.signing_request -> Cstruct.t
(** [pkcs1_digest_info_of_cstruct data] is [hash, signature], the hash and raw
signature or an error. *)
val pkcs1_digest_info_of_cstruct : Cstruct.t ->
(Nocrypto.Hash.hash * Cstruct.t, err) result
(** [pkcs1_digest_info_to_cstruct (hash, signature)] is [data], the encoded
hash and signature. *)
val pkcs1_digest_info_to_cstruct : Nocrypto.Hash.hash * Cstruct.t -> Cstruct.t
(** [rsa_public_to_cstruct pk] is [buffer], the ASN.1 encoding of the given
public key. *)
val rsa_public_to_cstruct : Nocrypto.Rsa.pub -> Cstruct.t
(** [rsa_public_of_cstruct buffer] is [pubkey], the public key of the ASN.1
encoded buffer. *)
val rsa_public_of_cstruct : Cstruct.t -> (Nocrypto.Rsa.pub, err) result
(** [public_key_to_cstruct pk] is [buffer], the ASN.1 encoding of the given
public key. *)
val public_key_to_cstruct : public_key -> Cstruct.t
(** [public_key_of_cstruct buffer] is [pubkey], the public key of the ASN.1
encoded buffer. *)
val public_key_of_cstruct : Cstruct.t -> (public_key, err) result
(** [crl_to_cstruct crl] is [buffer], the ASN.1 DER encoding of the given
certificate revocation list. *)
val crl_to_cstruct : CRL.c -> Cstruct.t
(** [crl_of_cstruct buffer] is [crl], the certificate revocation list of the
ASN.1 encoded buffer. *)
val crl_of_cstruct : Cstruct.t -> (CRL.c, err) result
(** Parser and unparser of PEM files *)
module Pem : sig
(** {2 PEM encoding} *)
(** [parse pem] is [(name * data) list], in which the [pem] is parsed into
its components, each surrounded by [BEGIN name] and [END name]. The
actual [data] is base64 decoded. *)
val parse : Cstruct.t -> ((string * Cstruct.t) list, err) result
(** Decoding and encoding of
{{:https://tools.ietf.org/html/rfc5280#section-3.1}X509 certificates}
in PEM format *)
module Certificate : sig
(** {3 PEM encoded certificates} *)
(** [of_pem_cstruct pem] is [t list], where all certificates of the [pem]
are extracted *)
val of_pem_cstruct : Cstruct.t -> (t list, err) result
(** [of_pem_cstruct1 pem] is [t], where the single certificate of the
[pem] is extracted *)
val of_pem_cstruct1 : Cstruct.t -> (t, err) result
(** [to_pem_cstruct certificates] is [pem], the pem encoded
certificates. *)
val to_pem_cstruct : t list -> Cstruct.t
(** [to_pem_cstruct1 certificate] is [pem], the pem encoded
certificate. *)
val to_pem_cstruct1 : t -> Cstruct.t
end
(** Decoding and encoding of
{{:https://tools.ietf.org/html/rfc2986}PKCS 10 certification requests}
in PEM format *)
module Certificate_signing_request : sig
(** {3 PEM encoded certificate signing requests} *)
(** [of_pem_cstruct pem] is [t list], where all signing requests of the
[pem] are extracted *)
val of_pem_cstruct : Cstruct.t ->
(CA.signing_request list, err) result
(** [of_pem_cstruct1 pem] is [t], where the single signing request of the
[pem] is extracted *)
val of_pem_cstruct1 : Cstruct.t -> (CA.signing_request, err) result
(** [to_pem_cstruct signing_requests] is [pem], the pem encoded
signing requests. *)
val to_pem_cstruct : CA.signing_request list -> Cstruct.t
(** [to_pem_cstruct1 signing_request] is [pem], the pem encoded
signing request. *)
val to_pem_cstruct1 : CA.signing_request -> Cstruct.t
end
(** Decoding and encoding of public keys in PEM format as defined in
{{:http://tools.ietf.org/html/rfc5208}PKCS 8} *)
module Public_key : sig
(** {3 PEM encoded RSA keys} *)
(** [of_pem_cstruct pem] is [t list], where all public keys of [pem] are
extracted *)
val of_pem_cstruct : Cstruct.t -> (public_key list, err) result
(** [of_pem_cstruct1 pem] is [t], where the public key of [pem] is
extracted *)
val of_pem_cstruct1 : Cstruct.t -> (public_key, err) result
(** [to_pem_cstruct public_keys] is [pem], the pem encoded public keys. *)
val to_pem_cstruct : public_key list -> Cstruct.t
(** [to_pem_cstruct1 public_key] is [pem], the pem encoded public key. *)
val to_pem_cstruct1 : public_key -> Cstruct.t
end
(** Decoding and encoding of unencrypted private RSA keys in PEM format as
defined in {{:http://tools.ietf.org/html/rfc5208}PKCS 8} *)
module Private_key : sig
(** {3 PEM encoded RSA keys} *)
(** [of_pem_cstruct pem] is [t list], where all private keys of [pem] are
extracted *)
val of_pem_cstruct : Cstruct.t -> (private_key list, err) result
(** [of_pem_cstruct1 pem] is [t], where the private key of [pem] is
extracted *)
val of_pem_cstruct1 : Cstruct.t -> (private_key, err) result
(** [to_pem_cstruct keys] is [pem], the pem encoded private keys. *)
val to_pem_cstruct : private_key list -> Cstruct.t
(** [to_pem_cstruct1 key] is [pem], the pem encoded private key. *)
val to_pem_cstruct1 : private_key -> Cstruct.t
end
end
end