utils.go (4208B)
1 package certificates 2 3 import ( 4 "bytes" 5 "crypto/rand" 6 "crypto/rsa" 7 "crypto/x509" 8 "crypto/x509/pkix" 9 "encoding/pem" 10 "errors" 11 "fmt" 12 "math" 13 "math/big" 14 "os" 15 "time" 16 17 "github.com/valyala/bytebufferpool" 18 ) 19 20 func readCertificate(filename string) (*x509.Certificate, error) { 21 data, err := os.ReadFile(filename) 22 if err != nil { 23 return nil, err 24 } 25 26 block, _ := pem.Decode(data) 27 if block == nil || block.Type != "CERTIFICATE" { 28 return nil, errors.New("invalid certificate") 29 } 30 31 cert, err := x509.ParseCertificate(block.Bytes) 32 if err != nil { 33 return nil, err 34 } 35 36 return cert, nil 37 } 38 39 func readKey(file string) (*rsa.PrivateKey, error) { 40 data, err := os.ReadFile(file) 41 if err != nil { 42 return nil, err 43 } 44 45 block, _ := pem.Decode(data) 46 if block.Type != "RSA PRIVATE KEY" { 47 return nil, errors.New("only rsa private key is supported") 48 } 49 50 return x509.ParsePKCS1PrivateKey(block.Bytes) 51 } 52 53 func generateCertificateImpl( 54 filename string, 55 template *x509.Certificate, 56 key *rsa.PrivateKey, 57 parent *x509.Certificate, 58 rootKey *rsa.PrivateKey, 59 ) ([]byte, error) { 60 if parent == nil { 61 parent = template 62 } 63 64 data, err := x509.CreateCertificate( 65 rand.Reader, 66 template, 67 parent, 68 key.Public(), 69 rootKey, 70 ) 71 if err != nil { 72 return nil, err 73 } 74 75 buf := bytebufferpool.Get() 76 defer bytebufferpool.Put(buf) 77 78 err = pem.Encode(buf, &pem.Block{ 79 Type: "CERTIFICATE", 80 Bytes: data, 81 }) 82 if err != nil { 83 return nil, fmt.Errorf("failed to encode certificate: %w", err) 84 } 85 86 err = os.WriteFile(filename, buf.B, 0600) 87 if err != nil { 88 return nil, err 89 } 90 91 return data, nil 92 } 93 94 func generateCertificate( 95 filename string, 96 domain string, 97 key *rsa.PrivateKey, 98 parent *x509.Certificate, 99 rootKey *rsa.PrivateKey, 100 ) ([]byte, error) { 101 serial, err := rand.Int(rand.Reader, big.NewInt(math.MaxInt64)) 102 if err != nil { 103 return nil, err 104 } 105 106 return generateCertificateImpl( 107 filename, 108 &x509.Certificate{ 109 DNSNames: []string{domain}, 110 Subject: pkix.Name{CommonName: domain}, 111 SerialNumber: serial, 112 NotBefore: time.Now(), 113 NotAfter: time.Now().AddDate(2, 0, 30), 114 KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment, 115 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}, 116 BasicConstraintsValid: true, 117 }, 118 key, 119 parent, 120 rootKey, 121 ) 122 } 123 124 func generateRootCertificate(filename string, key *rsa.PrivateKey) (*x509.Certificate, error) { 125 serial, err := rand.Int(rand.Reader, big.NewInt(math.MaxInt64)) 126 if err != nil { 127 return nil, err 128 } 129 130 template := &x509.Certificate{ 131 Subject: pkix.Name{ 132 CommonName: "Devroxy Internal CA ", 133 }, 134 SerialNumber: serial, 135 NotBefore: time.Now(), 136 NotAfter: time.Now().AddDate(2, 0, 30), 137 KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment, 138 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}, 139 BasicConstraintsValid: true, 140 IsCA: true, 141 } 142 143 data, err := generateCertificateImpl( 144 filename, 145 template, 146 key, 147 nil, 148 key, 149 ) 150 if err != nil { 151 return nil, err 152 } 153 154 return x509.ParseCertificate(data) 155 } 156 157 func generateKey(filename string) (*rsa.PrivateKey, error) { 158 key, err := rsa.GenerateKey(rand.Reader, 2048) 159 if err != nil { 160 return nil, err 161 } 162 err = writeKey(filename, key) 163 if err != nil { 164 return nil, err 165 } 166 return key, nil 167 } 168 169 func writeKey(file string, key *rsa.PrivateKey) error { 170 data := x509.MarshalPKCS1PrivateKey(key) 171 172 buf := bytebufferpool.Get() 173 defer bytebufferpool.Put(buf) 174 175 err := pem.Encode(buf, &pem.Block{ 176 Type: "RSA PRIVATE KEY", 177 Bytes: data, 178 }) 179 if err != nil { 180 return err 181 } 182 183 return os.WriteFile(file, buf.Bytes(), 0600) 184 } 185 186 func checkCertificate(cert *x509.Certificate, key *rsa.PrivateKey) error { 187 if cert.PublicKeyAlgorithm != x509.RSA { 188 return errors.New("only rsa certificate is supported") 189 } 190 191 dataA := x509.MarshalPKCS1PublicKey(cert.PublicKey.(*rsa.PublicKey)) 192 dataB := x509.MarshalPKCS1PublicKey(&key.PublicKey) 193 194 if !bytes.Equal(dataA, dataB) { 195 return errors.New("public key not match") 196 } 197 198 return nil 199 }