github.com/bigzoro/my_simplechain@v0.0.0-20240315012955-8ad0a2a29bb9/rpc/tls/common/utils.go (about) 1 package common 2 3 import ( 4 "crypto" 5 "crypto/ecdsa" 6 "crypto/rsa" 7 "crypto/tls" 8 "crypto/x509" 9 "encoding/pem" 10 "fmt" 11 "github.com/bigzoro/my_simplechain/log" 12 "github.com/pkg/errors" 13 "io/ioutil" 14 "os" 15 "strings" 16 "time" 17 ) 18 19 // FileExists checks to see if a file exists 20 func FileExists(name string) bool { 21 if _, err := os.Stat(name); err != nil { 22 if os.IsNotExist(err) { 23 return false 24 } 25 } 26 return true 27 } 28 29 // GetX509CertificateFromPEM get an X509 certificate from bytes in PEM format 30 func GetX509CertificateFromPEM(cert []byte) (*x509.Certificate, error) { 31 block, _ := pem.Decode(cert) 32 if block == nil { 33 return nil, errors.New("Failed to PEM decode certificate") 34 } 35 x509Cert, err := x509.ParseCertificate(block.Bytes) 36 if err != nil { 37 return nil, errors.Wrap(err, "Error parsing certificate") 38 } 39 return x509Cert, nil 40 } 41 42 // LoadX509KeyPair reads and parses a public/private key pair from a pair 43 // of files. The files must contain PEM encoded data. The certificate file 44 // may contain intermediate certificates following the leaf certificate to 45 // form a certificate chain. On successful return, Certificate.Leaf will 46 // be nil because the parsed form of the certificate is not retained. 47 func LoadX509KeyPair(certFile, keyFile string) (*tls.Certificate, error) { 48 certPEMBlock, err := ioutil.ReadFile(certFile) 49 if err != nil { 50 return nil, err 51 } 52 keyPEMBlock, err := ioutil.ReadFile(keyFile) 53 if err != nil { 54 return nil, err 55 } 56 return X509KeyPair(certPEMBlock, keyPEMBlock) 57 } 58 59 // X509KeyPair parses a public/private key pair from a pair of 60 // PEM encoded data. On successful return, Certificate.Leaf will be nil because 61 // the parsed form of the certificate is not retained. 62 func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (*tls.Certificate, error) { 63 fail := func(err error) (*tls.Certificate, error) { return nil, err } 64 65 var cert tls.Certificate 66 var skippedBlockTypes []string 67 for { 68 var certDERBlock *pem.Block 69 certDERBlock, certPEMBlock = pem.Decode(certPEMBlock) 70 if certDERBlock == nil { 71 break 72 } 73 if certDERBlock.Type == "CERTIFICATE" { 74 cert.Certificate = append(cert.Certificate, certDERBlock.Bytes) 75 } else { 76 skippedBlockTypes = append(skippedBlockTypes, certDERBlock.Type) 77 } 78 } 79 80 if len(cert.Certificate) == 0 { 81 if len(skippedBlockTypes) == 0 { 82 return fail(errors.New("tls: failed to find any PEM data in certificate input")) 83 } 84 if len(skippedBlockTypes) == 1 && strings.HasSuffix(skippedBlockTypes[0], "PRIVATE KEY") { 85 return fail(errors.New("tls: failed to find certificate PEM data in certificate input, but did find a private key; PEM inputs may have been switched")) 86 } 87 return fail(fmt.Errorf("tls: failed to find \"CERTIFICATE\" PEM block in certificate input after skipping PEM blocks of the following types: %v", skippedBlockTypes)) 88 } 89 90 skippedBlockTypes = skippedBlockTypes[:0] 91 var keyDERBlock *pem.Block 92 for { 93 keyDERBlock, keyPEMBlock = pem.Decode(keyPEMBlock) 94 if keyDERBlock == nil { 95 if len(skippedBlockTypes) == 0 { 96 return fail(errors.New("tls: failed to find any PEM data in key input")) 97 } 98 if len(skippedBlockTypes) == 1 && skippedBlockTypes[0] == "CERTIFICATE" { 99 return fail(errors.New("tls: found a certificate rather than a key in the PEM for the private key")) 100 } 101 return fail(fmt.Errorf("tls: failed to find PEM block with type ending in \"PRIVATE KEY\" in key input after skipping PEM blocks of the following types: %v", skippedBlockTypes)) 102 } 103 if keyDERBlock.Type == "PRIVATE KEY" || strings.HasSuffix(keyDERBlock.Type, " PRIVATE KEY") { 104 break 105 } 106 skippedBlockTypes = append(skippedBlockTypes, keyDERBlock.Type) 107 } 108 109 // We don't need to parse the public key for TLS, but we so do anyway 110 // to check that it looks sane and matches the private key. 111 x509Cert, err := x509.ParseCertificate(cert.Certificate[0]) 112 if err != nil { 113 return fail(err) 114 } 115 116 cert.PrivateKey, err = parsePrivateKey(keyDERBlock.Bytes) 117 if err != nil { 118 return fail(err) 119 } 120 121 switch pub := x509Cert.PublicKey.(type) { 122 case *rsa.PublicKey: 123 priv, ok := cert.PrivateKey.(*rsa.PrivateKey) 124 if !ok { 125 return fail(errors.New("tls: private key type does not match public key type")) 126 } 127 if pub.N.Cmp(priv.N) != 0 { 128 return fail(errors.New("tls: private key does not match public key")) 129 } 130 case *ecdsa.PublicKey: 131 priv, ok := cert.PrivateKey.(*ecdsa.PrivateKey) 132 if !ok { 133 return fail(errors.New("tls: private key type does not match public key type")) 134 } 135 if pub.X.Cmp(priv.X) != 0 || pub.Y.Cmp(priv.Y) != 0 { 136 return fail(errors.New("tls: private key does not match public key")) 137 } 138 default: 139 return fail(errors.New("tls: unknown public key algorithm")) 140 } 141 142 return &cert, nil 143 } 144 145 // Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates 146 // PKCS#1 private keys by default, while OpenSSL 1.0.0 generates PKCS#8 keys. 147 // OpenSSL ecparam generates SEC1 EC private keys for ECDSA. We try all three. 148 func parsePrivateKey(der []byte) (crypto.PrivateKey, error) { 149 if key, err := x509.ParsePKCS1PrivateKey(der); err == nil { 150 return key, nil 151 } 152 if key, err := x509.ParsePKCS8PrivateKey(der); err == nil { 153 switch key := key.(type) { 154 case *rsa.PrivateKey, *ecdsa.PrivateKey: 155 return key, nil 156 default: 157 return nil, errors.New("tls: found unknown private key type in PKCS#8 wrapping") 158 } 159 } 160 if key, err := x509.ParseECPrivateKey(der); err == nil { 161 return key, nil 162 } 163 164 return nil, errors.New("tls: failed to parse private key") 165 } 166 167 // LoadPEMCertPool loads a pool of PEM certificates from list of files 168 func LoadPEMCertPool(certFiles []string) (*x509.CertPool, error) { 169 certPool := x509.NewCertPool() 170 171 if len(certFiles) > 0 { 172 for _, cert := range certFiles { 173 log.Debug("Reading cert", "file", cert) 174 pemCerts, err := ioutil.ReadFile(cert) 175 if err != nil { 176 return nil, err 177 } 178 179 log.Debug("Appending cert", cert, "to pool") 180 if !certPool.AppendCertsFromPEM(pemCerts) { 181 return nil, errors.New("Failed to load cert pool") 182 } 183 } 184 } 185 186 return certPool, nil 187 } 188 189 func CheckCertDates(certFile string) error { 190 log.Debug("Check client TLS certificate for valid dates") 191 certPEM, err := ioutil.ReadFile(certFile) 192 if err != nil { 193 return errors.Wrapf(err, "Failed to read file '%s'", certFile) 194 } 195 196 cert, err := GetX509CertificateFromPEM(certPEM) 197 if err != nil { 198 return err 199 } 200 201 notAfter := cert.NotAfter 202 currentTime := time.Now().UTC() 203 204 if currentTime.After(notAfter) { 205 return errors.New("Certificate provided has expired") 206 } 207 208 notBefore := cert.NotBefore 209 if currentTime.Before(notBefore) { 210 return errors.New("Certificate provided not valid until later date") 211 } 212 213 return nil 214 }