github.com/cactusblossom/fabric-ca@v0.0.0-20200611062428-0082fc643826/lib/tcert/util.go (about) 1 /* 2 Copyright IBM Corp. 2016 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package tcert 18 19 import ( 20 "bytes" 21 "crypto/aes" 22 "crypto/cipher" 23 "crypto/ecdsa" 24 "crypto/rand" 25 "crypto/rsa" 26 "crypto/x509" 27 "encoding/base64" 28 "encoding/pem" 29 "errors" 30 "fmt" 31 "io" 32 "io/ioutil" 33 "math/big" 34 "time" 35 36 "github.com/cloudflare/cfssl/log" 37 ) 38 39 const ( 40 // AESKeyLength is the default AES key length 41 AESKeyLength = 32 42 ) 43 44 var ( 45 //RootPreKeySize is the default value of root key 46 RootPreKeySize = 48 47 ) 48 49 // GenerateIntUUID returns a UUID based on RFC 4122 returning a big.Int 50 func GenerateIntUUID() (*big.Int, error) { 51 uuid, err := GenerateBytesUUID() 52 if err != nil { 53 return nil, err 54 } 55 z := big.NewInt(0) 56 return z.SetBytes(uuid), nil 57 } 58 59 // GenerateBytesUUID returns a UUID based on RFC 4122 returning the generated bytes 60 func GenerateBytesUUID() ([]byte, error) { 61 uuid := make([]byte, 16) 62 _, err := io.ReadFull(rand.Reader, uuid) 63 if err != nil { 64 return nil, err 65 } 66 67 // variant bits; see section 4.1.1 68 uuid[8] = uuid[8]&^0xc0 | 0x80 69 70 // version 4 (pseudo-random); see section 4.1.3 71 uuid[6] = uuid[6]&^0xf0 | 0x40 72 73 return uuid, nil 74 } 75 76 // CBCPKCS7Encrypt combines CBC encryption and PKCS7 padding 77 func CBCPKCS7Encrypt(key, src []byte) ([]byte, error) { 78 return CBCEncrypt(key, PKCS7Padding(src)) 79 } 80 81 // CBCEncrypt encrypts using CBC mode 82 func CBCEncrypt(key, s []byte) ([]byte, error) { 83 // CBC mode works on blocks so plaintexts may need to be padded to the 84 // next whole block. For an example of such padding, see 85 // https://tools.ietf.org/html/rfc5246#section-6.2.3.2. Here we'll 86 // assume that the plaintext is already of the correct length. 87 if len(s)%aes.BlockSize != 0 { 88 return nil, errors.New("CBCEncrypt failure: plaintext is not a multiple of the block size") 89 } 90 91 block, err := aes.NewCipher(key) 92 if err != nil { 93 return nil, err 94 } 95 96 // The IV needs to be unique, but not secure. Therefore it's common to 97 // include it at the beginning of the ciphertext. 98 ciphertext := make([]byte, aes.BlockSize+len(s)) 99 iv := ciphertext[:aes.BlockSize] 100 if _, err := io.ReadFull(rand.Reader, iv); err != nil { 101 return nil, fmt.Errorf("CBCEncrypt failure in io.ReadFull: %s", err) 102 } 103 104 mode := cipher.NewCBCEncrypter(block, iv) 105 mode.CryptBlocks(ciphertext[aes.BlockSize:], s) 106 107 // It's important to remember that ciphertexts must be authenticated 108 // (i.e. by using crypto/hmac) as well as being encrypted in order to 109 // be secure. 110 return ciphertext, nil 111 } 112 113 // PKCS7Padding pads as prescribed by the PKCS7 standard 114 func PKCS7Padding(src []byte) []byte { 115 padding := aes.BlockSize - len(src)%aes.BlockSize 116 padtext := bytes.Repeat([]byte{byte(padding)}, padding) 117 return append(src, padtext...) 118 } 119 120 //ConvertDERToPEM returns data from DER to PEM format 121 //DERData is DER 122 func ConvertDERToPEM(der []byte, datatype string) []byte { 123 pemByte := pem.EncodeToMemory( 124 &pem.Block{ 125 Type: datatype, 126 Bytes: der, 127 }, 128 ) 129 return pemByte 130 } 131 132 //GenNumber generates random numbers of type *big.Int with fixed length 133 func GenNumber(numlen *big.Int) (*big.Int, error) { 134 lowerBound := new(big.Int).Exp(big.NewInt(10), new(big.Int).Sub(numlen, big.NewInt(1)), nil) 135 upperBound := new(big.Int).Exp(big.NewInt(10), numlen, nil) 136 randomNum, err := rand.Int(rand.Reader, upperBound) 137 if err != nil { 138 return nil, fmt.Errorf("Failed to generate random number: %s", err) 139 } 140 val := new(big.Int).Add(randomNum, lowerBound) 141 valMod := new(big.Int).Mod(val, upperBound) 142 143 if valMod.Cmp(lowerBound) == -1 { 144 newval := new(big.Int).Add(valMod, lowerBound) 145 return newval, nil 146 } 147 return valMod, nil 148 } 149 150 // GetEnrollmentIDFromCert retrieves Enrollment Id from certificate 151 func GetEnrollmentIDFromCert(ecert *x509.Certificate) string { 152 return ecert.Subject.CommonName 153 } 154 155 //GetCertificate returns interface containing *rsa.PublicKey or ecdsa.PublicKey 156 func GetCertificate(certificate []byte) (*x509.Certificate, error) { 157 158 var certificates []*x509.Certificate 159 var isvalidCert bool 160 var err error 161 162 block, _ := pem.Decode(certificate) 163 if block == nil { 164 certificates, err = x509.ParseCertificates(certificate) 165 if err != nil { 166 log.Error("Certificate Parse failed") 167 return nil, errors.New("DER Certificate Parse failed") 168 } //else { 169 isvalidCert = ValidateCert(certificates[0]) 170 if !isvalidCert { 171 log.Error("Certificate expired") 172 return nil, errors.New("Certificate expired") 173 } 174 //} 175 } else { 176 certificates, err = x509.ParseCertificates(block.Bytes) 177 if err != nil { 178 log.Error("PEM Certificatre Parse failed") 179 return nil, errors.New("PEM Certificate Parse failed") 180 } //else { 181 isvalidCert = ValidateCert(certificates[0]) 182 if !isvalidCert { 183 log.Error("Certificate expired") 184 return nil, errors.New("Certificate expired") 185 } 186 //} 187 } 188 return certificates[0], nil 189 190 } 191 192 //GetCertitificateSerialNumber returns serial number for Certificate byte 193 //return -1 , if there is problem with the cert 194 func GetCertitificateSerialNumber(certificatebyte []byte) (*big.Int, error) { 195 certificate, error := GetCertificate(certificatebyte) 196 if error != nil { 197 log.Error("Not a valid Certificate") 198 return big.NewInt(-1), error 199 } 200 return certificate.SerialNumber, nil 201 } 202 203 //ValidateCert checks for expiry in the certificate cert 204 //Does not check for revocation 205 func ValidateCert(cert *x509.Certificate) bool { 206 notBefore := cert.NotBefore 207 notAfter := cert.NotAfter 208 currentTime := time.Now() 209 diffFromExpiry := notAfter.Sub(currentTime) 210 diffFromStart := currentTime.Sub(notBefore) 211 return ((diffFromExpiry > 0) && (diffFromStart > 0)) 212 } 213 214 // CBCPKCS7Decrypt combines CBC decryption and PKCS7 unpadding 215 func CBCPKCS7Decrypt(key, src []byte) ([]byte, error) { 216 pt, err := CBCDecrypt(key, src) 217 if err != nil { 218 219 return nil, err 220 } 221 222 original, err := PKCS7UnPadding(pt) 223 if err != nil { 224 225 return nil, err 226 } 227 228 return original, nil 229 } 230 231 // CBCDecrypt decrypts using CBC mode 232 func CBCDecrypt(key, src []byte) ([]byte, error) { 233 block, err := aes.NewCipher(key) 234 if err != nil { 235 236 return nil, err 237 } 238 239 // The IV needs to be unique, but not secure. Therefore it's common to 240 // include it at the beginning of the ciphertext. 241 if len(src) < aes.BlockSize { 242 243 return nil, errors.New("ciphertext too short") 244 } 245 iv := src[:aes.BlockSize] 246 src = src[aes.BlockSize:] 247 248 // CBC mode always works in whole blocks. 249 if len(src)%aes.BlockSize != 0 { 250 251 return nil, errors.New("ciphertext is not a multiple of the block size") 252 } 253 254 mode := cipher.NewCBCDecrypter(block, iv) 255 256 // CryptBlocks can work in-place if the two arguments are the same. 257 mode.CryptBlocks(src, src) 258 259 // If the original plaintext lengths are not a multiple of the block 260 // size, padding would have to be added when encrypting, which would be 261 // removed at this point. For an example, see 262 // https://tools.ietf.org/html/rfc5246#section-6.2.3.2. However, it's 263 // critical to note that ciphertexts must be authenticated (i.e. by 264 // using crypto/hmac) before being decrypted in order to avoid creating 265 // a padding oracle. 266 267 return src, nil 268 } 269 270 // PKCS7UnPadding unpads as prescribed by the PKCS7 standard 271 func PKCS7UnPadding(src []byte) ([]byte, error) { 272 length := len(src) 273 unpadding := int(src[length-1]) 274 275 if unpadding > aes.BlockSize || unpadding == 0 { 276 return nil, fmt.Errorf("invalid padding") 277 } 278 279 pad := src[len(src)-unpadding:] 280 for i := 0; i < unpadding; i++ { 281 if pad[i] != byte(unpadding) { 282 return nil, fmt.Errorf("invalid padding") 283 } 284 } 285 286 return src[:(length - unpadding)], nil 287 } 288 289 //CreateRootPreKey method generates root key 290 func CreateRootPreKey() string { 291 var cooked string 292 key := make([]byte, RootPreKeySize) 293 rand.Reader.Read(key) 294 cooked = base64.StdEncoding.EncodeToString(key) 295 return cooked 296 } 297 298 // GetPrivateKey returns ecdsa.PrivateKey or rsa.privateKey object for the private Key Bytes 299 func GetPrivateKey(buf []byte) (interface{}, error) { 300 var err error 301 var privateKey interface{} 302 303 block, _ := pem.Decode(buf) 304 if block == nil { 305 privateKey, err = ParsePrivateKey(buf) 306 if err != nil { 307 return nil, fmt.Errorf("Failure parsing DER-encoded private key: %s", err) 308 } 309 } else { 310 privateKey, err = ParsePrivateKey(block.Bytes) 311 if err != nil { 312 return nil, fmt.Errorf("Failure parsing PEM private key: %s", err) 313 } 314 } 315 316 switch privateKey := privateKey.(type) { 317 case *rsa.PrivateKey: 318 return privateKey, nil 319 case *ecdsa.PrivateKey: 320 return privateKey, nil 321 default: 322 return nil, errors.New("Key is neither RSA nor ECDSA") 323 } 324 325 } 326 327 // ParsePrivateKey parses private key 328 func ParsePrivateKey(der []byte) (interface{}, error) { 329 if key, err := x509.ParsePKCS1PrivateKey(der); err == nil { 330 return key, nil 331 } 332 if key, err := x509.ParsePKCS8PrivateKey(der); err == nil { 333 switch key := key.(type) { 334 case *rsa.PrivateKey, *ecdsa.PrivateKey: 335 return key, nil 336 default: 337 return nil, errors.New("Key is neither RSA nor ECDSA") 338 } 339 } 340 key, err := x509.ParseECPrivateKey(der) 341 if err != nil { 342 return nil, fmt.Errorf("Failure parsing private key: %s", err) 343 } 344 return key, nil 345 } 346 347 // LoadCert loads a certificate from a file 348 func LoadCert(path string) (*x509.Certificate, error) { 349 certBuf, err := ioutil.ReadFile(path) 350 if err != nil { 351 return nil, err 352 } 353 return GetCertificate(certBuf) 354 } 355 356 // LoadKey loads a private key from a file 357 func LoadKey(path string) (interface{}, error) { 358 keyBuf, err := ioutil.ReadFile(path) 359 if err != nil { 360 return nil, err 361 } 362 key, err := GetPrivateKey(keyBuf) 363 if err != nil { 364 return nil, err 365 } 366 return key, nil 367 }