github.com/hoffie/larasync@v0.0.0-20151025221940-0384d2bddcef/helpers/x509/fingerprint.go (about) 1 package x509 2 3 import ( 4 "crypto/sha512" 5 "crypto/x509" 6 "encoding/hex" 7 "encoding/pem" 8 "errors" 9 "io/ioutil" 10 ) 11 12 // CertificateFingerprint returns the SHA-512 fingerprint of the given certificate 13 // as a hex-encoded string. 14 // 15 // Note that this algorithm is *not* compatible with the one used in browsers. 16 // This is for two reasons: 17 // Firstly, currentl (2015) browsers do not show sha512 fingerprints anway 18 // (sha256 and sha1 only). 19 // Secondly, we do not care about the certificate at all (it contains standardized 20 // field contents only). Instead we want to verify the public key. This is what 21 // we do here. 22 // 23 // The algorithm is taken from 24 // http://tools.ietf.org/html/draft-ietf-websec-key-pinning-01#ref-why-pin-key 25 // but uses sha512 instead of sha1. 26 func CertificateFingerprint(cert *x509.Certificate) string { 27 h := sha512.New() 28 h.Write(cert.RawSubjectPublicKeyInfo) 29 sum := h.Sum(nil) 30 return hex.EncodeToString(sum) 31 } 32 33 // CertificateFingerprintFromBytes parses the given certificate bytes and returns its 34 // fingerprint. 35 func CertificateFingerprintFromBytes(cert []byte) (string, error) { 36 parsed, err := x509.ParseCertificate(cert) 37 if err != nil { 38 return "", err 39 } 40 return CertificateFingerprint(parsed), nil 41 } 42 43 // CertificateFingerprintFromPEMFile loads the given PEM file and returns its 44 // fingerprint. 45 func CertificateFingerprintFromPEMFile(path string) (string, error) { 46 pemBytes, err := ioutil.ReadFile(path) 47 if err != nil { 48 return "", err 49 } 50 block, _ := pem.Decode(pemBytes) 51 if block == nil { 52 return "", errors.New("unable to parse PEM block") 53 } 54 return CertificateFingerprintFromBytes(block.Bytes) 55 }