123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159moduleLog=Capnp_rpc.Debug.Logletdefault_rsa_key_bits=2048letdefault_hash=`SHA256typehash=[`SHA256](* Note: if we add more hashes here, we need to modify [Vat] to store *all*
hashes of peer's public keys when they connect. Otherwise, we might record
a client as "sha-256:abc" but it later refers to itself in a sturdy ref as
"sha-512:def". We need to detect it's the same peer. *)leterrorfmt=fmt|>Fmt.kstr@@funmsg->Error(`Msgmsg)let(>>=)xf=matchxwith|Oky->fy|Error_ase->emoduleDigest=structtypet=[`Insecure|`Fingerprintofhash*string]letequal=(=)letinsecure=`Insecureletalphabet=Base64.uri_safe_alphabetletstring_of_hash=function|`SHA256->"sha-256"letparse_hash=function|"sha-256"->Ok`SHA256|x->error"Unknown hash type %S"xletparse_digests=B64.decode~alphabet~pad:falsesletparsehashdigest=parse_hashhash>>=funhash->parse_digestdigest>>=fundigest->Ok(hash,digest)letof_certificatecert:t=lethash=default_hashinletdigest=X509.Public_key.fingerprint~hash(X509.Certificate.public_keycert)in`Fingerprint(hash,digest)letadd_to_urituri=matchtwith|`Insecure->Uri.with_userinfouri(Some"insecure")|`Fingerprint(hash,digest)->lethash=string_of_hashhashinletdigest=B64.encode~alphabet~pad:falsedigestinleturi=Uri.with_userinfouri(Somehash)inUri.with_passworduri(Somedigest)letppf=function|`Insecure->Fmt.stringf"insecure"|`Fingerprint(hash,digest)->Fmt.pff"%s@%s"(string_of_hashhash)(B64.encode~alphabet~pad:falsedigest)letfrom_uriuri=lethash_type=Uri.useruriinletdigest=Uri.passworduriinmatchhash_type,digestwith|Some"insecure",None->Ok`Insecure|Somehash,Somedigest->parsehashdigest>>=fundigest->Ok(`Fingerprintdigest)|None,_->Error(`Msg"Missing digest hash type (e.g. '...://sha256:...')")|Some_,None->Error(`Msg"Missing digest value (e.g. '...://sha256:DIGEST@...' or '...://insecure@...')")letauthenticator=function|`Insecure->None|`Fingerprint(hash,digest)->lethash=(hash:>Digestif.hash')inSome(X509.Authenticator.key_fingerprint~hash~fingerprint:digest~time:(fun_->None))moduleMap=Map.Make(structtypenonrect=tletcompare=compareend)endmoduleSecret_key=structtypet={priv:X509.Private_key.t;certificates:Tls.Config.own_cert;tls_server_config:Tls.Config.server;}letequalab=a.priv=b.privlettls_server_configt=t.tls_server_configlettls_client_configt~authenticator=matchTls.Config.client~certificates:t.certificates~authenticator()with|Okx->x|Error(`Msgmsg)->Fmt.failwith"tls_client_config: %s"msgletdigest?(hash=default_hash)t=letnc_hash=(hash:>Digestif.hash')inletpub=X509.Private_key.publict.privinletvalue=X509.Public_key.fingerprint~hash:nc_hashpubin`Fingerprint(hash,value)letpp_fingerprinthashft=Digest.ppf(digest~hasht)letdate_time~date~time=lettz_offset_s=0inmatchPtime.of_date_time(date,(time,tz_offset_s))with|Somedt->dt|None->failwith"Invalid date_time!"letx509t=letdn=[X509.Distinguished_name.(Relative_distinguished_name.singleton(CN"capnp"))]inmatchX509.Signing_request.createdntwith|Error(`Msgm)->Fmt.failwith"x509 certificate signing request creation failed %s"m|Okcsr->letvalid_from=date_time~date:(1970,1,1)~time:(1,1,1)in(* RFC 5280 says expiration date should be GeneralizedTime value 99991231235959Z *)letvalid_until=date_time~date:(9999,12,31)~time:(23,59,59)inX509.Signing_request.signcsr~valid_from~valid_untiltdn|>function|Okv->v|Errorerr->Fmt.failwith"x509 signing failed: %a"X509.Validation.pp_signature_errorerrletof_privpriv=letcert=x509privinletcertificates=`Single([cert],priv)in(* We require a client cert to get the client's public key, although
we allow any client to connect. We just want to know they key so that
if we later need to resolve a sturdy ref hosted at the client, we can
reuse this connection. *)letauthenticator?ip:_~host:__=OkNoneinmatchTls.Config.server~certificates~authenticator()with|Oktls_server_config->{priv;certificates;tls_server_config}|Error(`Msgm)->Fmt.failwith"Invalid TLS configuration: %s"mletgenerate()=Log.info(funf->f"Generating new private key...");letpriv=Mirage_crypto_pk.Rsa.generate~bits:default_rsa_key_bits()inlett=of_priv(`RSApriv)inLog.info(funf->f"Generated key with hash %a"(pp_fingerprint`SHA256)t);tletof_pem_datadata=matchX509.Private_key.decode_pemdatawith|Okpriv->of_privpriv|Error(`Msgmsg)->Fmt.failwith"Failed to parse secret key!@ %s"msgletto_pem_datat=X509.Private_key.encode_pemt.privend