Documentation
¶
Overview ¶
Package direct is Direct secure messaging as an edge system: a message to a Direct address is signed with this address's certificate and encrypted to the recipient's, as S/MIME, and sent to a HISP by SMTP; a message received from the HISP (by SMTP or collected over IMAP) is decrypted and its signature checked against the trust anchors before anything reads it.
It follows the Direct Project Applicability Statement for Secure Health Transport 1.2 and the XDM specification (IHE ITI TF-1 Annex 15) for documents with metadata. It is not a HISP: the HISP's accreditation, its certificate policy and its directory stay with the HISP.
Index ¶
- Variables
- func DNSCertificates(ctx context.Context, address, server string) ([]*x509.Certificate, error)
- func FindCertificates(ctx context.Context, address, dnsServer, ldapServer string) ([]*x509.Certificate, string, error)
- func LDAPCertificates(ctx context.Context, address, server string) ([]*x509.Certificate, error)
- func Protect(m Message, sender cms.KeyPair, chain []*x509.Certificate, ...) ([]byte, error)
- func WriteXDM(metadata []byte, docs map[string][]byte, readme string) ([]byte, error)
- func XDMFor(req *xds.SubmitObjectsRequest, name string, content []byte) ([]byte, error)
- type Attachment
- type Checker
- type Disposition
- type Message
- type Opened
- type Receiver
- type XDMDocument
Constants ¶
This section is empty.
Variables ¶
var ErrUntrusted = errors.New("direct: the message is not signed by a trusted sender")
ErrUntrusted is a message whose signature does not lead to a trust anchor.
Functions ¶
func DNSCertificates ¶
DNSCertificates looks up the certificates for a Direct address: the address-bound ones, else the domain's. server is a resolver (host:port); empty uses the system's first nameserver.
func FindCertificates ¶ added in v0.1.19
func FindCertificates(ctx context.Context, address, dnsServer, ldapServer string) ([]*x509.Certificate, string, error)
FindCertificates looks a recipient's certificates up the ways the certificate discovery guide allows, DNS first, then LDAP; ldapServer "off" skips the directory. It says where they were found.
func LDAPCertificates ¶ added in v0.1.19
LDAPCertificates finds the certificates published for a Direct address in its domain's LDAP directory: the second discovery method of the Direct Project's certificate discovery guide, after DNS CERT records. The directory is server (host:port) when given, else the ones the domain's _ldap._tcp SRV records name, in their priority order. Each is asked anonymously for its naming contexts, then, under each, for an entry whose mail is the address and its userSMIMECertificate (or userCertificate); with none, for an entry whose mail is the domain (a domain-bound certificate). Only certificates are read, so the bind is anonymous and the connection may be plain: what is found is checked against the trust anchors afterwards, exactly like a certificate found in DNS.
func Protect ¶
func Protect(m Message, sender cms.KeyPair, chain []*x509.Certificate, recipients []*x509.Certificate) ([]byte, error)
Protect builds the RFC 5322 message the HISP receives: the content signed (multipart/signed, SHA-256) by sender's certificate, and that whole entity encrypted (application/pkcs7-mime enveloped-data) to every recipient certificate and the sender's own, so the sender can read what it sent. Headers a HISP routes by (From, To, Message-ID, Date) stay outside.
Types ¶
type Attachment ¶
Attachment is one part of a Direct message.
type Checker ¶ added in v0.1.19
type Checker struct {
Anchors *x509.CertPool
// Now is the time certificates are checked at; time.Now when nil.
Now func() time.Time
// Client fetches issuers and revocation lists; nil means one that refuses the cloud metadata address (egress).
Client *http.Client
// contains filtered or unexported fields
}
Checker decides whether a certificate found for a recipient may be encrypted to: it must chain to a trust anchor, fetching intermediate issuers named by its Authority Information Access extension when the chain is not complete, and it must not be revoked on its issuers' certificate revocation lists. Both are what the Direct Applicability Statement (4.2.2) asks for and what ONC's certificate discovery tool tests (D17, D18).
Revocation fails open: a list that cannot be fetched or read does not stop delivery, because a CRL server that is down would otherwise stop all Direct mail to everyone the authority issued for. A certificate listed as revoked, on a list its issuer signed, is always refused.
type Disposition ¶
type Disposition struct {
Kind, OriginalMessageID string
}
Disposition is an MDN's report.
type Message ¶
type Message struct {
From, Subject string
To []string
Text string
Attachments []Attachment
MessageID string
Date time.Time
// DispositionNotification asks the recipient for an MDN (the Direct Implementation Guide for Delivery Notification).
DispositionNotification bool
}
Message is a Direct message before it is protected, or after it is opened.
type Opened ¶
type Opened struct {
Message
// Signer is the certificate that signed it, checked to a trust anchor.
Signer *x509.Certificate
// SignerAddress is the Direct address (or domain) the signer's certificate is for.
SignerAddress string
// XDM is the documents and metadata when an attachment is an XDM package.
XDM []XDMDocument
// MDN is the disposition notification when the message is one: its kind (processed, dispatched, failed) and the
// Message-ID it is about.
MDN *Disposition
}
Opened is a received message after decryption and signature checking.
func Open ¶
Open reads a message from the HISP: decrypts it with whichever of keys it was encrypted to, verifies the signature against anchors, and checks that the signing certificate belongs to the From address (or its domain), as the Applicability Statement requires. An unsigned, untrusted or misattributed message is an error: it is never passed on as if it were Direct.
type Receiver ¶
type Receiver struct {
Hostname string
// Accept says whether mail for an address is taken.
Accept func(rcpt string) bool
// Deliver is given each message; an error refuses it.
Deliver func(ctx context.Context, from string, to []string, raw []byte) error
TLS *tls.Config
// RequireTLS refuses MAIL before STARTTLS.
RequireTLS bool
MaxBytes int64
Log *slog.Logger
}
Receiver is the SMTP server a HISP delivers a Direct address's mail to: the Direct "edge" side of SMTP. It accepts mail only for the addresses it holds certificates for, requires STARTTLS before MAIL when it has a certificate (a Direct message is encrypted end to end, and the hop is protected as well), and hands each message to Deliver. A message Deliver refuses is refused at DATA with the reason, so the HISP keeps it and reports it.
type XDMDocument ¶
type XDMDocument struct {
Name, MimeType, Title, PatientID, UniqueID, TypeCode string
Content []byte
}
XDMDocument is one document from an XDM package, with what its metadata says.
func ReadXDM ¶
func ReadXDM(zipped []byte) ([]XDMDocument, error)
ReadXDM reads an XDM package's documents and what its METADATA.XML says about each (by the URI slot that names the file).