Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file tls_lwt.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265openLwtexceptionTls_alertofTls.Packet.alert_typeexceptionTls_failureofTls.Engine.failureletofgx=f(gx)(* This really belongs just about anywhere else: generic unix name resolution. *)letresolvehostservice=letopenLwt_unixingetprotobyname"tcp">>=funtcp->getaddrinfohostservice[AI_PROTOCOLtcp.p_proto]>>=function|[]->letmsg=Printf.sprintf"no address for %s:%s"hostserviceinfail(Invalid_argumentmsg)|ai::_->returnai.ai_addrmoduleLwt_cs=structletnaked~nameffdcs=Cstruct.(ffdcs.buffercs.offcs.len)>>=funres->matchLwt_unix.getsockopt_errorfdwith|None->returnres|Someerr->fail@@Unix.Unix_error(err,name,"")letwrite=naked~name:"Tls_lwt.write"Lwt_bytes.writeandread=naked~name:"Tls_lwt.read"Lwt_bytes.readletrecwrite_fullfd=function|cswhenCstruct.lencs=0->return_unit|cs->writefdcs>>=o(write_fullfd)(Cstruct.shiftcs)endmoduleUnix=structtypet={fd:Lwt_unix.file_descr;mutablestate:[`ActiveofTls.Engine.state|`Eof|`Errorofexn];mutablelinger:Cstruct.toption;}letsafelyth=Lwt.catch(fun()->th>>=fun_->return_unit)(fun_->return_unit)let(read_t,write_t)=letrecording_errorsoptcs=Lwt.catch(fun()->opt.fdcs)(funexn->(matcht.statewith|`Error_|`Eof->()|`Active_->t.state<-`Errorexn);failexn)in(recording_errorsLwt_cs.read,recording_errorsLwt_cs.write_full)letwhen_somef=functionNone->return_unit|Somex->fxletrecv_buf=Cstruct.create4096letrecread_reactt=lethandletlsbuf=matchTls.Engine.handle_tlstlsbufwith|`Ok(state',`Responseresp,`Datadata)->letstate'=matchstate'with|`Oktls->`Activetls|`Eof->`Eof|`Alerta->`Error(Tls_alerta)int.state<-state';safely(resp|>when_some(write_tt))>|=fun()->`Okdata|`Fail(alert,`Responseresp)->t.state<-`Error(Tls_failurealert);write_ttresp>>=fun()->read_reacttinmatcht.statewith|`Errore->faile|`Eof->return`Eof|`Active_->read_ttrecv_buf>>=funn->match(t.state,n)with|(`Active_,0)->t.state<-`Eof;return`Eof|(`Activetls,n)->handletls(Cstruct.subrecv_buf0n)|(`Errore,_)->faile|(`Eof,_)->return`Eofletrecreadtbuf=letwriteoutres=letopenCstructinletrlen=lenresinletn=min(lenbuf)rleninblitres0buf0n;t.linger<-(ifn<rlenthenSome(subresn(rlen-n))elseNone);returnninmatcht.lingerwith|Someres->writeoutres|None->read_reactt>>=function|`Eof->return0|`OkNone->readtbuf|`Ok(Someres)->writeoutresletwritevtcss=matcht.statewith|`Errorerr->failerr|`Eof->fail@@Invalid_argument"tls: closed socket"|`Activetls->matchTls.Engine.send_application_datatlscsswith|Some(tls,tlsdata)->(t.state<-`Activetls;write_tttlsdata)|None->fail@@Invalid_argument"tls: write: socket not ready"letwritetcs=writevt[cs](*
* XXX bad XXX
* This is a point that should particularly be protected from concurrent r/w.
* Doing this before a `t` is returned is safe; redoing it during rekeying is
* not, as the API client already sees the `t` and can mistakenly interleave
* writes while this is in progress.
* *)letrecdrain_handshaket=letpush_lingertmcs=letopenTls.Utils.Csinmatch(mcs,t.linger)with|(None,_)->()|(scs,None)->t.linger<-scs|(Somecs,Somel)->t.linger<-Some(l<+>cs)inmatcht.statewith|`Activetlswhennot(Tls.Engine.handshake_in_progresstls)->returnt|_->read_reactt>>=function|`Eof->failEnd_of_file|`Okcs->push_lingertcs;drain_handshaketletreneg?authenticator?acceptable_cas?cert?(drop=true)t=matcht.statewith|`Errorerr->failerr|`Eof->fail@@Invalid_argument"tls: closed socket"|`Activetls->matchTls.Engine.reneg?authenticator?acceptable_cas?certtlswith|None->fail@@Invalid_argument"tls: can't renegotiate"|Some(tls',buf)->ifdropthent.linger<-None;t.state<-`Activetls';write_ttbuf>>=fun()->drain_handshaket>>=fun_->return_unitletkey_update?requestt=matcht.statewith|`Errorerr->failerr|`Eof->fail@@Invalid_argument"tls: closed socket"|`Activetls->matchTls.Engine.key_update?requesttlswith|Error_->fail@@Invalid_argument"tls: can't update key"|Ok(tls',buf)->t.state<-`Activetls';write_ttbufletclose_tlst=matcht.statewith|`Activetls->let(_,buf)=Tls.Engine.send_close_notifytlsint.state<-`Eof;write_ttbuf|_->return_unitletcloset=safely(close_tlst)>>=fun()->Lwt_unix.closet.fdletserver_of_fdconfigfd=drain_handshake{state=`Active(Tls.Engine.serverconfig);fd=fd;linger=None;}letclient_of_fdconfig?hostfd=letconfig'=matchhostwith|None->config|Somehost->Tls.Config.peerconfighostinlett={state=`Eof;fd=fd;linger=None;}inlet(tls,init)=Tls.Engine.clientconfig'inlett={twithstate=`Activetls}inwrite_ttinit>>=fun()->drain_handshaketletacceptconffd=Lwt_unix.acceptfd>>=fun(fd',addr)->Lwt.catch(fun()->server_of_fdconffd'>|=funt->(t,addr))(funexn->safely(Lwt_unix.closefd')>>=fun()->failexn)letconnectconf(host,port)=resolvehost(string_of_intport)>>=funaddr->letfd=Lwt_unix.(socket(Unix.domain_of_sockaddraddr)SOCK_STREAM0)inLwt.catch(fun()->Lwt_unix.connectfdaddr>>=fun()->client_of_fdconf~hostfd)(funexn->safely(Lwt_unix.closefd)>>=fun()->failexn)letread_bytestbsofflen=readt(Cstruct.of_bigarray~off~lenbs)letwrite_bytestbsofflen=writet(Cstruct.of_bigarray~off~lenbs)letepocht=matcht.statewith|`Activetls->(matchTls.Engine.epochtlswith|`InitialEpoch->assertfalse(* can never occur! *)|`Epochdata->`Okdata)|`Eof->`Error|`Error_->`Errorendtypeic=Lwt_io.input_channeltypeoc=Lwt_io.output_channelletof_t?closet=letclose=matchclosewith|Somef->(fun()->Unix.safely(f()))|None->(fun()->(* avoid double-closes by checking if the fd has already been closed *)matchLwt_unix.statet.Unix.fdwith|Lwt_unix.Closed->Lwt.return_unit|Lwt_unix.Opened|Lwt_unix.Aborted_->Unix.(safely(closet)))in(Lwt_io.make~close~mode:Lwt_io.Input(Unix.read_bytest)),(Lwt_io.make~close~mode:Lwt_io.Output@@funabc->Unix.write_bytestabc>>=fun()->returnc)letaccept_extconffd=Unix.acceptconffd>|=fun(t,peer)->(of_tt,peer)andconnect_extconfaddr=Unix.connectconfaddr>|=of_tletacceptcertificate=letconfig=Tls.Config.server~certificates:certificate()inaccept_extconfigandconnectauthenticatoraddr=letconfig=Tls.Config.client~authenticator()inconnect_extconfigaddr(* Boot the entropy loop at module init time. *)let()=Mirage_crypto_rng_unix.initialize()