github.com/Schaudge/grailbase@v0.0.0-20240223061707-44c758a471c0/security/ticket/tls.go (about) 1 // Copyright 2018 GRAIL, Inc. All rights reserved. 2 // Use of this source code is governed by the Apache-2.0 3 // license that can be found in the LICENSE file. 4 5 package ticket 6 7 import ( 8 "bytes" 9 "crypto/x509" 10 "encoding/pem" 11 "time" 12 13 "github.com/Schaudge/grailbase/common/log" 14 "github.com/Schaudge/grailbase/security/keycrypt" 15 "github.com/Schaudge/grailbase/security/tls/certificateauthority" 16 ) 17 18 const tlsDriftMargin = 10 * time.Minute 19 20 func (b *TlsCertAuthorityBuilder) newTlsClientTicket(ctx *TicketContext) (TicketTlsClientTicket, error) { 21 tlsCredentials, err := b.genTlsCredentials(ctx) 22 23 if err != nil { 24 return TicketTlsClientTicket{}, err 25 } 26 27 return TicketTlsClientTicket{ 28 Value: TlsClientTicket{ 29 Credentials: tlsCredentials, 30 }, 31 }, nil 32 } 33 34 func (b *TlsCertAuthorityBuilder) newTlsServerTicket(ctx *TicketContext) (TicketTlsServerTicket, error) { 35 tlsCredentials, err := b.genTlsCredentials(ctx) 36 37 if err != nil { 38 return TicketTlsServerTicket{}, err 39 } 40 41 return TicketTlsServerTicket{ 42 Value: TlsServerTicket{ 43 Credentials: tlsCredentials, 44 }, 45 }, nil 46 } 47 48 func (b *TlsCertAuthorityBuilder) newDockerTicket(ctx *TicketContext) (TicketDockerTicket, error) { 49 tlsCredentials, err := b.genTlsCredentials(ctx) 50 51 if err != nil { 52 return TicketDockerTicket{}, err 53 } 54 55 return TicketDockerTicket{ 56 Value: DockerTicket{ 57 Credentials: tlsCredentials, 58 }, 59 }, nil 60 } 61 62 func (b *TlsCertAuthorityBuilder) newDockerServerTicket(ctx *TicketContext) (TicketDockerServerTicket, error) { 63 tlsCredentials, err := b.genTlsCredentialsWithKeyUsage(ctx, []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}) 64 65 if err != nil { 66 return TicketDockerServerTicket{}, err 67 } 68 69 return TicketDockerServerTicket{ 70 Value: DockerServerTicket{ 71 Credentials: tlsCredentials, 72 }, 73 }, nil 74 } 75 76 func (b *TlsCertAuthorityBuilder) newDockerClientTicket(ctx *TicketContext) (TicketDockerClientTicket, error) { 77 tlsCredentials, err := b.genTlsCredentialsWithKeyUsage(ctx, []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}) 78 79 if err != nil { 80 return TicketDockerClientTicket{}, err 81 } 82 83 return TicketDockerClientTicket{ 84 Value: DockerClientTicket{ 85 Credentials: tlsCredentials, 86 }, 87 }, nil 88 } 89 90 func (b *TlsCertAuthorityBuilder) genTlsCredentials(ctx *TicketContext) (TlsCredentials, error) { 91 log.Info(ctx.ctx, "Generating TLS credentials.", "TlsCertAuthorityBuilder", b) 92 return b.genTlsCredentialsWithKeyUsage(ctx, []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}) 93 } 94 95 func contains(array []string, entry string) bool { 96 for _, e := range array { 97 if e == entry { 98 return true 99 } 100 } 101 102 return false 103 } 104 105 func (b *TlsCertAuthorityBuilder) genTlsCredentialsWithKeyUsage(ctx *TicketContext, keyUsage []x509.ExtKeyUsage) (TlsCredentials, error) { 106 empty := TlsCredentials{} 107 108 secret, err := keycrypt.Lookup(b.Authority) 109 if err != nil { 110 return empty, err 111 } 112 authority := certificateauthority.CertificateAuthority{DriftMargin: tlsDriftMargin, Signer: secret} 113 if err := authority.Init(); err != nil { 114 return empty, err 115 } 116 ttl := time.Duration(b.TtlSec) * time.Second 117 commonName := b.CommonName 118 if commonName == "" { 119 commonName = ctx.remoteBlessings.String() 120 } 121 updatedSan := b.San 122 if !contains(updatedSan, commonName) { 123 updatedSan = append(updatedSan, commonName) 124 } 125 cert, key, err := authority.IssueWithKeyUsage(commonName, ttl, nil, updatedSan, keyUsage) 126 if err != nil { 127 return empty, err 128 } 129 130 r := TlsCredentials{} 131 r.AuthorityCert, err = encode(&pem.Block{Type: "CERTIFICATE", Bytes: authority.Cert.Raw}) 132 if err != nil { 133 return empty, err 134 } 135 r.Cert, err = encode(&pem.Block{Type: "CERTIFICATE", Bytes: cert}) 136 if err != nil { 137 return empty, err 138 } 139 r.Key, err = encode(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)}) 140 if err != nil { 141 return empty, err 142 } 143 return r, nil 144 } 145 146 func encode(block *pem.Block) (string, error) { 147 var w bytes.Buffer 148 if err := pem.Encode(&w, block); err != nil { 149 return "", err 150 } 151 return w.String(), nil 152 }