+50
@@ -0,0 +1,50 @@
|
||||
// Package fingerprint provides a helper to create fingerprint string from certificate
|
||||
package fingerprint
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var (
|
||||
errHashUnavailable = errors.New("fingerprint: hash algorithm is not linked into the binary")
|
||||
errInvalidFingerprintLength = errors.New("fingerprint: invalid fingerprint length")
|
||||
)
|
||||
|
||||
// Fingerprint creates a fingerprint for a certificate using the specified hash algorithm
|
||||
func Fingerprint(cert *x509.Certificate, algo crypto.Hash) (string, error) {
|
||||
if !algo.Available() {
|
||||
return "", errHashUnavailable
|
||||
}
|
||||
h := algo.New()
|
||||
for i := 0; i < len(cert.Raw); {
|
||||
n, _ := h.Write(cert.Raw[i:])
|
||||
// Hash.Writer is specified to be never returning an error.
|
||||
// https://golang.org/pkg/hash/#Hash
|
||||
i += n
|
||||
}
|
||||
digest := []byte(fmt.Sprintf("%x", h.Sum(nil)))
|
||||
|
||||
digestlen := len(digest)
|
||||
if digestlen == 0 {
|
||||
return "", nil
|
||||
}
|
||||
if digestlen%2 != 0 {
|
||||
return "", errInvalidFingerprintLength
|
||||
}
|
||||
res := make([]byte, digestlen>>1+digestlen-1)
|
||||
|
||||
pos := 0
|
||||
for i, c := range digest {
|
||||
res[pos] = c
|
||||
pos++
|
||||
if (i)%2 != 0 && i < digestlen-1 {
|
||||
res[pos] = byte(':')
|
||||
pos++
|
||||
}
|
||||
}
|
||||
|
||||
return string(res), nil
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package fingerprint
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"errors"
|
||||
)
|
||||
|
||||
var errInvalidHashAlgorithm = errors.New("fingerprint: invalid hash algorithm")
|
||||
|
||||
func nameToHash() map[string]crypto.Hash {
|
||||
return map[string]crypto.Hash{
|
||||
"md5": crypto.MD5, // [RFC3279]
|
||||
"sha-1": crypto.SHA1, // [RFC3279]
|
||||
"sha-224": crypto.SHA224, // [RFC4055]
|
||||
"sha-256": crypto.SHA256, // [RFC4055]
|
||||
"sha-384": crypto.SHA384, // [RFC4055]
|
||||
"sha-512": crypto.SHA512, // [RFC4055]
|
||||
}
|
||||
}
|
||||
|
||||
// HashFromString allows looking up a hash algorithm by it's string representation
|
||||
func HashFromString(s string) (crypto.Hash, error) {
|
||||
if h, ok := nameToHash()[s]; ok {
|
||||
return h, nil
|
||||
}
|
||||
return 0, errInvalidHashAlgorithm
|
||||
}
|
||||
|
||||
// StringFromHash allows looking up a string representation of the crypto.Hash.
|
||||
func StringFromHash(hash crypto.Hash) (string, error) {
|
||||
for s, h := range nameToHash() {
|
||||
if h == hash {
|
||||
return s, nil
|
||||
}
|
||||
}
|
||||
return "", errInvalidHashAlgorithm
|
||||
}
|
||||
Reference in New Issue
Block a user