Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PKCS12 #114

Draft
wants to merge 11 commits into
base: master
from

parsing: use result instead of option and exceptions

  • Loading branch information...
hannesm committed Apr 22, 2019
commit d05151da5908649534811023244f6ee99d8dc471
@@ -5,13 +5,12 @@ open Asn.S
let def x = function None -> x | Some y -> y
let def' x = fun y -> if y = x then None else Some y

let decode codec cs = match Asn.decode codec cs with
| Error e -> Error e
| Ok (a, cs) ->
if Cstruct.len cs = 0 then Ok a else Error (`Parse "Leftovers")
let decode codec cs =
let open Rresult.R.Infix in
Asn.decode codec cs >>= fun (a, cs) ->
if Cstruct.len cs = 0 then Ok a else Error (`Parse "Leftovers")

let projections_of encoding asn =
let decode c cs = match decode c cs with Ok a -> Some a | _ -> None in
let c = Asn.codec encoding asn in (decode c, Asn.encode c)

let compare_unordered_lists cmp l1 l2 =
@@ -7,4 +7,4 @@
x509_encoding x509_extension_types x509_extension x509_pem
x509_request_types x509_types)
(flags (:standard -safe-string))
(libraries asn1-combinators ptime cstruct nocrypto astring))
(libraries asn1-combinators rresult fmt ptime cstruct nocrypto astring))
@@ -676,36 +676,40 @@ end
(** Encodings *)
module Encoding : sig

type err = Asn.error

val pp_err : err Fmt.t

(** {1 ASN.1 Encoding} *)

(** [parse cstruct] is [certificate option], the ASN.1 decoded
[certificate] or [None]. *)
val parse : Cstruct.t -> t option
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 option
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 option],
the ASN.1 decoded [cstruct] or [None]. *)
val parse_signing_request : Cstruct.t -> CA.signing_request option
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
val cs_of_signing_request : CA.signing_request -> Cstruct.t

(** [pkcs1_digest_info_of_cstruct data] is [hash, signature option],
the hash and raw signature. *)
val pkcs1_digest_info_of_cstruct : Cstruct.t ->
(Nocrypto.Hash.hash * Cstruct.t) option
(Nocrypto.Hash.hash * Cstruct.t, err) result

(** [pkcs1_digest_info_to_cstruct (hash, signature)] is [data], the
encoded hash and signature. *)
@@ -717,23 +721,23 @@ module Encoding : sig

(** [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 option
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 option
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 option
val crl_of_cstruct : Cstruct.t -> (CRL.c, err) result

(** Parser and unparser of PEM files *)
module Pem : sig
@@ -743,7 +747,7 @@ module Encoding : sig
(** [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
val parse : Cstruct.t -> ((string * Cstruct.t) list, err) result

(** Decoding and encoding of
{{:https://tools.ietf.org/html/rfc5280#section-3.1}X509
@@ -754,11 +758,11 @@ module Encoding : sig

(** [of_pem_cstruct pem] is [t list], where all certificates of
the [pem] are extracted *)
val of_pem_cstruct : Cstruct.t -> t list
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
val of_pem_cstruct1 : Cstruct.t -> (t, err) result

(** [to_pem_cstruct certificates] is [pem], the pem encoded
certificates. *)
@@ -776,23 +780,22 @@ module Encoding : sig

(** {3 PEM encoded certificate signing requests} *)

type t = CA.signing_request

(** [of_pem_cstruct pem] is [t list], where all signing requests
of the [pem] are extracted *)
val of_pem_cstruct : Cstruct.t -> t list
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 -> t
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 : t list -> Cstruct.t
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 : t -> Cstruct.t
val to_pem_cstruct1 : CA.signing_request -> Cstruct.t
end

(** Decoding and encoding of public keys in PEM format as defined
@@ -803,11 +806,11 @@ module Encoding : sig

(** [of_pem_cstruct pem] is [t list], where all public keys of
[pem] are extracted *)
val of_pem_cstruct : Cstruct.t -> public_key list
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
val of_pem_cstruct1 : Cstruct.t -> (public_key, err) result

(** [to_pem_cstruct public_keys] is [pem], the pem encoded
public keys. *)
@@ -827,11 +830,11 @@ module Encoding : sig

(** [of_pem_cstruct pem] is [t list], where all private keys of
[pem] are extracted *)
val of_pem_cstruct : Cstruct.t -> private_key list
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
val of_pem_cstruct1 : Cstruct.t -> (private_key, err) result

(** [to_pem_cstruct private_keys] is [pem], the pem encoded
private keys. *)
@@ -10,31 +10,22 @@ let raw_sign raw digest key =
match key with
| `RSA priv -> Nocrypto.Rsa.PKCS1.sig_encode ~key:priv sigval

type signing_request = CertificateRequest.certificate_request * Cstruct.t option
type signing_request = CertificateRequest.certificate_request

let info (sr, _) = sr.CertificateRequest.info
let info sr = sr.CertificateRequest.info

let validate_signature ({ CertificateRequest.info ; signature ; signature_algorithm }, raw) =
let raw = match raw with
| None -> CertificateRequest.certificate_request_info_to_cs info
| Some x -> raw_cert_hack x signature
in
validate_raw_signature
raw
signature_algorithm
signature
info.public_key
let validate_signature { CertificateRequest.info ; signature ; signature_algorithm } =
(* TODO: may be wrong if remote used some non-utf string encoding *)
let raw = CertificateRequest.certificate_request_info_to_cs info in
validate_raw_signature raw signature_algorithm signature info.public_key

let parse_signing_request cs =
match CertificateRequest.certificate_request_of_cs cs with
| Some csr when validate_signature (csr, Some cs) ->
Some (csr, Some cs)
| _ -> None

let cs_of_signing_request (csr, raw) =
match raw with
| Some x -> x
| None -> CertificateRequest.certificate_request_to_cs csr
let open Rresult.R.Infix in
CertificateRequest.certificate_request_of_cs cs >>= fun csr ->
if validate_signature csr then
Ok csr
else
Error (`Parse "couldn't validate signature")

let request subject ?(digest = `SHA256) ?(extensions = []) = function
| `RSA priv ->
@@ -43,18 +34,18 @@ let request subject ?(digest = `SHA256) ?(extensions = []) = function
let info_cs = CertificateRequest.certificate_request_info_to_cs info in
let signature = raw_sign info_cs digest (`RSA priv) in
let signature_algorithm = Algorithm.of_signature_algorithm `RSA digest in
({ CertificateRequest.info ; signature_algorithm ; signature }, None)
{ CertificateRequest.info ; signature_algorithm ; signature }

let sign signing_request
~valid_from ~valid_until
?(digest = `SHA256)
?(serial = Nocrypto.(Rng.Z.gen_r Numeric.Z.one Numeric.Z.(one lsl 64)))
?(extensions = [])
key issuer =
assert (validate_signature signing_request) ;
assert (validate_signature signing_request);
let signature_algo =
Algorithm.of_signature_algorithm (private_key_to_keytype key) digest
and info = (fst signing_request).CertificateRequest.info
and info = signing_request.CertificateRequest.info
in
let tbs_cert : tBSCertificate = {
version = `V3 ;
@@ -32,9 +32,9 @@ let serial { asn ; _ } = asn.tbs_cert.serial
let validity { asn ; _ } = asn.tbs_cert.validity

let parse_certificate cs =
match certificate_of_cstruct cs with
| None -> None
| Some asn -> Some { asn ; raw = cs }
let open Rresult.R.Infix in
certificate_of_cstruct cs >>| fun asn ->
{ asn ; raw = cs }

let cs_of_cert { raw ; _ } = raw

@@ -159,8 +159,8 @@ let validate_raw_signature raw signature_algo signature_val pk_info =
pkcs1_digest_info_of_cstruct signature,
Algorithm.to_signature_algorithm signature_algo
with
| Some (algo, hash), Some (`RSA, h) when h = algo ->
Cstruct.equal hash (Hash.digest algo raw)
| Ok (algo, hash), Some (`RSA, h) ->
h = algo && Cstruct.equal hash (Hash.digest algo raw)
| _ -> false )
| _ -> false

@@ -1,6 +1,8 @@
open Asn_grammars.CRL
include X509_crl_types

open Rresult

type c = {
raw : Cstruct.t ;
asn : Asn_grammars.CRL.t ;
@@ -9,9 +11,8 @@ type c = {
let crl_to_cstruct { raw ; _ } = raw

let crl_of_cstruct raw =
match crl_of_cstruct raw with
| None -> None
| Some asn -> Some { raw ; asn }
crl_of_cstruct raw >>| fun asn ->
{ raw ; asn }

let issuer { asn ; _ } = asn.tbs_crl.issuer

@@ -1,4 +1,9 @@

type err = Asn.error

let pp_err ppf = function
| `Parse msg -> Fmt.string ppf msg

let parse = X509_certificate.parse_certificate

let cs_of_cert = X509_certificate.cs_of_cert
@@ -9,9 +14,10 @@ let cs_of_distinguished_name = Asn_grammars.Name.name_to_cstruct

let parse_signing_request = X509_ca.parse_signing_request

let cs_of_signing_request = X509_ca.cs_of_signing_request
let cs_of_signing_request =
Asn_grammars.CertificateRequest.certificate_request_to_cs

let pkcs1_digest_info_of_cstruct : Cstruct.t -> (Nocrypto.Hash.hash * Cstruct.t) option =
let pkcs1_digest_info_of_cstruct : Cstruct.t -> (Nocrypto.Hash.hash * Cstruct.t, Asn.error) result =
Asn_grammars.pkcs1_digest_info_of_cstruct

let pkcs1_digest_info_to_cstruct : (Nocrypto.Hash.hash * Cstruct.t) -> Cstruct.t =
@@ -20,7 +26,7 @@ let pkcs1_digest_info_to_cstruct : (Nocrypto.Hash.hash * Cstruct.t) -> Cstruct.t
let rsa_public_to_cstruct : Nocrypto.Rsa.pub -> Cstruct.t =
Asn_grammars.PK.rsa_public_to_cstruct

let rsa_public_of_cstruct : Cstruct.t -> Nocrypto.Rsa.pub option =
let rsa_public_of_cstruct : Cstruct.t -> (Nocrypto.Rsa.pub, Asn.error) result =
Asn_grammars.PK.rsa_public_of_cstruct

let public_key_to_cstruct = Asn_grammars.PK.pub_info_to_cstruct
@@ -29,8 +35,7 @@ let public_key_of_cstruct = Asn_grammars.PK.pub_info_of_cstruct
let crl_to_cstruct : X509_crl.c -> Cstruct.t =
X509_crl.crl_to_cstruct

let crl_of_cstruct : Cstruct.t -> X509_crl.c option =
let crl_of_cstruct : Cstruct.t -> (X509_crl.c, Asn.error) result =
X509_crl.crl_of_cstruct

module Pem = X509_pem

ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.