]> Sergey Matveev's repositories - tofuproxy.git/blob - x509.go
Unify copyright comment format
[tofuproxy.git] / x509.go
1 // tofuproxy -- flexible HTTP/HTTPS proxy, TLS terminator, X.509 TOFU
2 //              manager, WARC/geminispace browser
3 // Copyright (C) 2021-2024 Sergey Matveev <stargrave@stargrave.org>
4 //
5 // This program is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, version 3 of the License.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
17 package tofuproxy
18
19 import (
20         "crypto"
21         "crypto/ecdsa"
22         "crypto/ed25519"
23         "crypto/elliptic"
24         "crypto/rand"
25         "crypto/x509"
26         "crypto/x509/pkix"
27         "log"
28         "math/big"
29         "sync"
30         "time"
31 )
32
33 type X509Keypair struct {
34         cert *x509.Certificate
35         prv  crypto.PrivateKey
36 }
37
38 var (
39         hostCerts  = make(map[string]*X509Keypair)
40         hostCertsM sync.Mutex
41         Serial     *big.Int
42         X509Algo   string
43 )
44
45 func init() {
46         max := big.NewInt(0)
47         max = max.SetBit(max, 128, 1)
48         var err error
49         Serial, err = rand.Int(rand.Reader, max)
50         if err != nil {
51                 panic(err)
52         }
53 }
54
55 func NewKeypair(ai string) (pub, prv any) {
56         switch ai {
57         case "ecdsa":
58                 prvEcdsa, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
59                 if err != nil {
60                         log.Fatalln(err)
61                 }
62                 prv = prvEcdsa
63                 pub = prvEcdsa.Public()
64         case "eddsa":
65                 var err error
66                 pub, prv, err = ed25519.GenerateKey(rand.Reader)
67                 if err != nil {
68                         log.Fatalln(err)
69                 }
70         default:
71                 log.Fatalln("unknown algorithm specified")
72         }
73         return
74 }
75
76 func newX509Keypair(
77         host string,
78         caCert *x509.Certificate,
79         caPrv crypto.PrivateKey,
80 ) *X509Keypair {
81         pub, prv := NewKeypair(X509Algo)
82         notBefore := time.Now()
83         notAfter := notBefore.Add(24 * time.Hour)
84         Serial = Serial.Add(Serial, big.NewInt(1))
85         template := x509.Certificate{
86                 SerialNumber: Serial,
87                 Subject:      pkix.Name{CommonName: host},
88                 DNSNames:     []string{host},
89                 NotBefore:    notBefore,
90                 NotAfter:     notAfter,
91         }
92         certRaw, err := x509.CreateCertificate(
93                 rand.Reader, &template, caCert, pub, caPrv,
94         )
95         if err != nil {
96                 log.Fatalln(err)
97         }
98         cert, err := x509.ParseCertificate(certRaw)
99         if err != nil {
100                 log.Fatalln(err)
101         }
102         return &X509Keypair{cert, prv}
103 }