Skip to content
File

Blob: tun/server/keyless_rpc.go

go93 lines
1package server
2 
3import (
4 "context"
5 "crypto"
6 "crypto/rand"
7 "crypto/tls"
8 
9 "go.miragespace.co/specter/spec/acme"
10 "go.miragespace.co/specter/spec/protocol"
11 
12 "github.com/twitchtv/twirp"
13)
14 
15func (s *Server) getCertificate(ctx context.Context, proof *protocol.ProofOfWork, hostname string) (*tls.Certificate, error) {
16 token, client, err := extractAuthenticated(ctx)
17 if err != nil {
18 return nil, err
19 }
20 
21 normalized, err := acme.Normalize(hostname)
22 if err != nil {
23 return nil, twirp.InvalidArgumentError("hostname", err.Error())
24 }
25 
26 found, err := s.checkAcme(ctx, normalized, proof, token, client)
27 if err != nil {
28 return nil, err
29 }
30 
31 if !found {
32 return nil, twirp.PermissionDenied.Error("cannot use provided hostname for keyless tls")
33 }
34 
35 ret, cacheErr := s.keylessCache.Get(ctx, normalized)
36 if ret.err != nil {
37 return nil, ret.err
38 }
39 if cacheErr != nil {
40 return nil, cacheErr
41 }
42 
43 return ret.cert, nil
44}
45 
46func (s *Server) GetCertificate(ctx context.Context, req *protocol.KeylessGetCertificateRequest) (*protocol.KeylessGetCertificateResponse, error) {
47 cert, err := s.getCertificate(ctx, req.GetProof(), req.GetHostname())
48 if err != nil {
49 return nil, err
50 }
51 
52 return &protocol.KeylessGetCertificateResponse{
53 Certificates: cert.Certificate,
54 }, nil
55}
56 
57func (s *Server) Sign(ctx context.Context, req *protocol.KeylessSignRequest) (*protocol.KeylessSignResponse, error) {
58 cert, err := s.getCertificate(ctx, req.GetProof(), req.GetHostname())
59 if err != nil {
60 return nil, err
61 }
62 
63 var opts crypto.SignerOpts
64 switch req.GetAlgo() {
65 case protocol.KeylessSignRequest_SHA256:
66 opts = crypto.SHA256
67 case protocol.KeylessSignRequest_SHA384:
68 opts = crypto.SHA384
69 case protocol.KeylessSignRequest_SHA512:
70 opts = crypto.SHA512
71 default:
72 return nil, twirp.InvalidArgumentError("algo", "unsupported hash algorithm")
73 }
74 
75 signer, ok := cert.PrivateKey.(crypto.Signer)
76 if !ok {
77 return nil, twirp.InternalError("private key is not a crypto.Signer")
78 }
79 
80 if len(req.GetDigest()) != opts.HashFunc().Size() {
81 return nil, twirp.InvalidArgumentError("digest", "invalid digest length")
82 }
83 
84 sig, err := signer.Sign(rand.Reader, req.Digest, opts)
85 if err != nil {
86 return nil, twirp.InternalErrorWith(err)
87 }
88 
89 return &protocol.KeylessSignResponse{
90 Signature: sig,
91 }, nil
92}