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