Repository: smallstep/crypto
Pull request #88 (2022-10-05 05:41:04)

Bump github.com/aws/aws-sdk-go from 1.44.37 to 1.44.111
Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.44.37 to 1.44.111.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/aws/aws-sdk-go/releases">github.com/aws/aws-sdk-go's releases</a>.</em></p>
<blockquote>
<h1>Release v1.44.111 (2022-10-04)</h1>
<h3>Service Client Updates</h3>
<ul>
<li><code>service/connect</code>: Updates service API</li>
<li><code>service/connectcases</code>: Adds new service</li>
<li><code>service/ec2</code>: Updates service API and documentation
<ul>
<li>Added EnableNetworkAddressUsageMetrics flag for ModifyVpcAttribute, DescribeVpcAttribute APIs.</li>
</ul>
</li>
<li><code>service/ecs</code>: Updates service documentation
<ul>
<li>Documentation updates to address various Amazon ECS tickets.</li>
</ul>
</li>
<li><code>service/s3control</code>: Updates service API
<ul>
<li>S3 Object Lambda adds support to allow customers to intercept HeadObject and ListObjects requests and introduce their own compute. These requests were previously proxied to S3.</li>
</ul>
</li>
<li><code>service/workmail</code>: Updates service API, documentation, and paginators
<ul>
<li>This release adds support for impersonation roles in Amazon WorkMail.</li>
</ul>
</li>
</ul>
<h1>Release v1.44.110 (2022-10-03)</h1>
<h3>Service Client Updates</h3>
<ul>
<li><code>service/accessanalyzer</code>: Updates service API and documentation</li>
<li><code>service/ec2</code>: Updates service API and documentation
<ul>
<li>Adding an imdsSupport attribute to EC2 AMIs</li>
</ul>
</li>
<li><code>service/snowball</code>: Updates service API, documentation, and paginators
<ul>
<li>Adds support for V3_5C. This is a refreshed AWS Snowball Edge Compute Optimized device type with 28TB SSD, 104 vCPU and 416GB memory (customer usable).</li>
</ul>
</li>
</ul>
<h1>Release v1.44.109 (2022-09-30)</h1>
<h3>Service Client Updates</h3>
<ul>
<li><code>service/codedeploy</code>: Updates service API and documentation
<ul>
<li>This release allows you to override the alarm configurations when creating a deployment.</li>
</ul>
</li>
<li><code>service/devops-guru</code>: Updates service API and documentation</li>
<li><code>service/dlm</code>: Updates service API and documentation</li>
<li><code>service/runtime.sagemaker</code>: Updates service API and documentation</li>
<li><code>service/sagemaker</code>: Updates service API and documentation
<ul>
<li>A new parameter called ExplainerConfig is added to CreateEndpointConfig API to enable SageMaker Clarify online explainability feature.</li>
</ul>
</li>
<li><code>service/sso-oidc</code>: Updates service documentation</li>
</ul>
<h1>Release v1.44.108 (2022-09-29)</h1>
<h3>Service Client Updates</h3>
<ul>
<li><code>service/acm</code>: Updates service API and documentation
<ul>
<li>This update returns additional certificate details such as certificate SANs and allows sorting in the ListCertificates API.</li>
</ul>
</li>
<li><code>service/ec2</code>: Updates service API
<ul>
<li>u-3tb1 instances are powered by Intel Xeon Platinum 8176M (Skylake) processors and are purpose-built to run large in-memory databases.</li>
</ul>
</li>
<li><code>service/emr-serverless</code>: Updates service API and documentation</li>
<li><code>service/fsx</code>: Updates service API, documentation, and paginators</li>
<li><code>service/migrationhuborchestrator</code>: Adds new service</li>
<li><code>service/polly</code>: Updates service API</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/aws/aws-sdk-go/commit/2389894af92747d3ccd38b691ab977789ad489b1"><code>2389894</code></a> Release v1.44.111 (2022-10-04) (<a href="https://github-redirect.dependabot.com/aws/aws-sdk-go/issues/4576">#4576</a>)</li>
<li><a href="https://github.com/aws/aws-sdk-go/commit/0f8d80ad965ca2342a74a32cf5302fd992e11ab5"><code>0f8d80a</code></a> Release v1.44.110 (2022-10-03) (<a href="https://github-redirect.dependabot.com/aws/aws-sdk-go/issues/4575">#4575</a>)</li>
<li><a href="https://github.com/aws/aws-sdk-go/commit/5bd00c9522bfc83aa31845c54b28b4695d35a240"><code>5bd00c9</code></a> Release v1.44.109 (2022-09-30) (<a href="https://github-redirect.dependabot.com/aws/aws-sdk-go/issues/4574">#4574</a>)</li>
<li><a href="https://github.com/aws/aws-sdk-go/commit/05ed0fb059a261c43ff20d6b513f0813db86f7e4"><code>05ed0fb</code></a> Release v1.44.108 (2022-09-29) (<a href="https://github-redirect.dependabot.com/aws/aws-sdk-go/issues/4573">#4573</a>)</li>
<li><a href="https://github.com/aws/aws-sdk-go/commit/427f0372a6a485ae717e9b2a0b8f94766966901a"><code>427f037</code></a> Release v1.44.107 (2022-09-27) (<a href="https://github-redirect.dependabot.com/aws/aws-sdk-go/issues/4571">#4571</a>)</li>
<li><a href="https://github.com/aws/aws-sdk-go/commit/9f1279c1fa696efeb5b33cefe40fe8f08a23660b"><code>9f1279c</code></a> Release v1.44.106 (2022-09-26) (<a href="https://github-redirect.dependabot.com/aws/aws-sdk-go/issues/4568">#4568</a>)</li>
<li><a href="https://github.com/aws/aws-sdk-go/commit/5a9633d0f53573ccdf43270c0ce198fb369193b0"><code>5a9633d</code></a> Release v1.44.105 (2022-09-23) (<a href="https://github-redirect.dependabot.com/aws/aws-sdk-go/issues/4567">#4567</a>)</li>
<li><a href="https://github.com/aws/aws-sdk-go/commit/60cc9e7832f0444f132aeea2637cb5b1ab0498ca"><code>60cc9e7</code></a> Release v1.44.104 (2022-09-22) (<a href="https://github-redirect.dependabot.com/aws/aws-sdk-go/issues/4566">#4566</a>)</li>
<li><a href="https://github.com/aws/aws-sdk-go/commit/2ea5e80f6fe4f38caa0188cb74657d0485a1d177"><code>2ea5e80</code></a> Release v1.44.103 (2022-09-21) (<a href="https://github-redirect.dependabot.com/aws/aws-sdk-go/issues/4565">#4565</a>)</li>
<li><a href="https://github.com/aws/aws-sdk-go/commit/242f055e1f88dee7e2114039c24ab1dafdef896e"><code>242f055</code></a> Release v1.44.102 (2022-09-20) (<a href="https://github-redirect.dependabot.com/aws/aws-sdk-go/issues/4562">#4562</a>)</li>
<li>Additional commits viewable in <a href="https://github.com/aws/aws-sdk-go/compare/v1.44.37...v1.44.111">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/aws/aws-sdk-go&package-manager=go_modules&previous-version=1.44.37&new-version=1.44.111)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>


Patch:
diff --git a/README.md b/README.md
index e91f391..763c827 100644
--- a/README.md
+++ b/README.md
@@ -75,8 +75,3 @@ or just a YubiKey or an ssh-agent. On the cloud it supports:
 * [Amazon AWS KMS](https://aws.amazon.com/kms/)
 * [Google Cloud Key Management](https://cloud.google.com/security-key-management)
 * [Microsoft Azure Key Vault](https://azure.microsoft.com/en-us/services/key-vault/)
-
-### fingerprint
-
-Package `fingerprint` provides methods for creating and encoding X.509
-certificate, SSH certificate and SSH key fingerprints.
diff --git a/fingerprint/fingerprint.go b/fingerprint/fingerprint.go
deleted file mode 100644
index 6eb174b..0000000
--- a/fingerprint/fingerprint.go
+++ /dev/null
@@ -1,78 +0,0 @@
-package fingerprint
-
-import (
-	"crypto"
-	"encoding/base64"
-	"encoding/hex"
-	"fmt"
-	"strings"
-
-	"go.step.sm/crypto/internal/emoji"
-)
-
-// Encoding defines the supported encodings for certificates and key
-// fingerprints.
-//
-// This type is the base for sshutil.FingerprintEncoding and
-// x509util.FingerprintEncoding types.
-type Encoding int
-
-const (
-	// HexFingerprint represents the hex encoding of the fingerprint.
-	//
-	// This is the default encoding for an X.509 certificate.
-	HexFingerprint Encoding = iota + 1
-	// Base64Fingerprint represents the base64 encoding of the fingerprint.
-	//
-	// This is the default encoding for a public key.
-	Base64Fingerprint
-	// Base64URLFingerprint represents the base64URL encoding of the fingerprint.
-	Base64URLFingerprint
-	// Base64RawFingerprint represents the base64RawStd encoding of the
-	// fingerprint.
-	//
-	// This is the default encoding for an SSH key and certificate.
-	Base64RawFingerprint
-	// Base64RawURLFingerprint represents the base64RawURL encoding of the fingerprint.
-	Base64RawURLFingerprint
-	// EmojiFingerprint represents the emoji encoding of the fingerprint.
-	EmojiFingerprint
-)
-
-// New creates a fingerprint of the given data by hashing it and returns it in
-// the encoding format.
-func New(data []byte, h crypto.Hash, encoding Encoding) (string, error) {
-	if !h.Available() {
-		return "", fmt.Errorf("hash function %q is not available", h.String())
-	}
-	hash := h.New()
-	if _, err := hash.Write(data); err != nil {
-		return "", fmt.Errorf("error creating hash: %w", err)
-	}
-	fp := Fingerprint(hash.Sum(nil), encoding)
-	if fp == "" {
-		return "", fmt.Errorf("unknown encoding value %d", encoding)
-	}
-	return fp, nil
-}
-
-// Fingerprint encodes the given digest using the encoding format. If an invalid
-// encoding is passed, the return value will be an empty string.
-func Fingerprint(digest []byte, encoding Encoding) string {
-	switch encoding {
-	case HexFingerprint:
-		return strings.ToLower(hex.EncodeToString(digest))
-	case Base64Fingerprint:
-		return base64.StdEncoding.EncodeToString(digest)
-	case Base64URLFingerprint:
-		return base64.URLEncoding.EncodeToString(digest)
-	case Base64RawFingerprint:
-		return base64.RawStdEncoding.EncodeToString(digest)
-	case Base64RawURLFingerprint:
-		return base64.RawURLEncoding.EncodeToString(digest)
-	case EmojiFingerprint:
-		return emoji.Emoji(digest)
-	default:
-		return ""
-	}
-}
diff --git a/go.mod b/go.mod
index 1c4a164..270c699 100644
--- a/go.mod
+++ b/go.mod
@@ -11,7 +11,7 @@ require (
 	github.com/Azure/go-autorest/autorest/date v0.3.0
 	github.com/Masterminds/sprig/v3 v3.2.2
 	github.com/ThalesIgnite/crypto11 v1.2.5
-	github.com/aws/aws-sdk-go v1.44.37
+	github.com/aws/aws-sdk-go v1.44.111
 	github.com/go-piv/piv-go v1.10.0
 	github.com/golang/mock v1.6.0
 	github.com/googleapis/gax-go/v2 v2.5.1
@@ -20,7 +20,7 @@ require (
 	github.com/stretchr/testify v1.8.0
 	golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90
 	golang.org/x/net v0.0.0-20220909164309-bea034e7d591
-	google.golang.org/api v0.98.0
+	google.golang.org/api v0.97.0
 	google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252
 	google.golang.org/grpc v1.48.0
 	gopkg.in/square/go-jose.v2 v2.6.0
diff --git a/go.sum b/go.sum
index 16116e3..1be7b60 100644
--- a/go.sum
+++ b/go.sum
@@ -101,8 +101,8 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE
 github.com/ThalesIgnite/crypto11 v1.2.5 h1:1IiIIEqYmBvUYFeMnHqRft4bwf/O36jryEUpY+9ef8E=
 github.com/ThalesIgnite/crypto11 v1.2.5/go.mod h1:ILDKtnCKiQ7zRoNxcp36Y1ZR8LBPmR2E23+wTQe/MlE=
 github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
-github.com/aws/aws-sdk-go v1.44.37 h1:KvDxCX6dfJeEDC77U5GPGSP0ErecmNnhDHFxw+NIvlI=
-github.com/aws/aws-sdk-go v1.44.37/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
+github.com/aws/aws-sdk-go v1.44.111 h1:AcWfOgeedSQ4gQVwcIe6aLxpQNJMloZQyqnr7Dzki+s=
+github.com/aws/aws-sdk-go v1.44.111/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
 github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@@ -607,8 +607,8 @@ google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69
 google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=
 google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg=
 google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o=
-google.golang.org/api v0.98.0 h1:yxZrcxXESimy6r6mdL5Q6EnZwmewDJK2dVg3g75s5Dg=
-google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=
+google.golang.org/api v0.97.0 h1:x/vEL1XDF/2V4xzdNgFPaKHluRESo2aTsL7QzHnBtGQ=
+google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
diff --git a/sshutil/fingerprint.go b/sshutil/fingerprint.go
index 0017584..d66cc98 100644
--- a/sshutil/fingerprint.go
+++ b/sshutil/fingerprint.go
@@ -4,58 +4,68 @@ import (
 	"crypto/dsa" //nolint:staticcheck // support for DSA fingerprints
 	"crypto/rsa"
 	"crypto/sha256"
+	"encoding/base64"
+	"encoding/hex"
 	"fmt"
+	"strings"
 
 	"github.com/pkg/errors"
-	"go.step.sm/crypto/fingerprint"
+	"go.step.sm/crypto/internal/emoji"
 	"golang.org/x/crypto/ssh"
 )
 
 // FingerprintEncoding defines the supported encodings for SSH key and
 // certificate fingerprints.
-type FingerprintEncoding = fingerprint.Encoding
+type FingerprintEncoding int
 
 // Supported fingerprint encodings.
 const (
-	// DefaultFingerprint represents base64RawStd encoding of the fingerprint.
-	DefaultFingerprint = FingerprintEncoding(0)
-	// HexFingerprint represents the hex encoding of the fingerprint.
-	HexFingerprint = fingerprint.HexFingerprint
+	// Base64RawFingerprint represents the base64RawStd encoding of the
+	// fingerprint. This is the default encoding for an SSH key.
+	Base64RawFingerprint FingerprintEncoding = iota
+	// Base64RawURLFingerprint represents the base64RawURL encoding of the
+	// fingerprint.
+	Base64RawURLFingerprint
 	// Base64Fingerprint represents the base64 encoding of the fingerprint.
-	Base64Fingerprint = fingerprint.Base64Fingerprint
-	// Base64URLFingerprint represents the base64URL encoding of the fingerprint.
-	Base64URLFingerprint = fingerprint.Base64URLFingerprint
-	// Base64RawFingerprint represents the base64RawStd encoding of the fingerprint.
-	Base64RawFingerprint = fingerprint.Base64RawFingerprint
-	// Base64RawURLFingerprint represents the base64RawURL encoding of the fingerprint.
-	Base64RawURLFingerprint = fingerprint.Base64RawURLFingerprint
+	Base64Fingerprint
+	// Base64UrlFingerprint represents the base64URL encoding of the
+	// fingerprint.
+	Base64UrlFingerprint FingerprintEncoding = iota
+	// HexFingerprint represents the hex encoding of the fingerprint.
+	HexFingerprint
 	// EmojiFingerprint represents the emoji encoding of the fingerprint.
-	EmojiFingerprint = fingerprint.EmojiFingerprint
+	EmojiFingerprint
 )
 
 // Fingerprint returns the SHA-256 fingerprint of an ssh public key or
 // certificate.
 func Fingerprint(pub ssh.PublicKey) string {
-	return EncodedFingerprint(pub, DefaultFingerprint)
+	return EncodedFingerprint(pub, Base64RawFingerprint)
 }
 
 // EncodedFingerprint returns the SHA-256 hash of an ssh public key or
 // certificate using the specified encoding. If an invalid encoding is passed,
 // the return value will be an empty string.
 func EncodedFingerprint(pub ssh.PublicKey, encoding FingerprintEncoding) string {
-	var fp string
+	const prefix = "SHA256:"
 
 	sum := sha256.Sum256(pub.Marshal())
 	switch encoding {
-	case DefaultFingerprint:
-		fp = fingerprint.Fingerprint(sum[:], Base64RawFingerprint)
+	case Base64RawFingerprint:
+		return prefix + base64.RawStdEncoding.EncodeToString(sum[:])
+	case Base64RawURLFingerprint:
+		return prefix + base64.RawURLEncoding.EncodeToString(sum[:])
+	case Base64Fingerprint:
+		return prefix + base64.StdEncoding.EncodeToString(sum[:])
+	case Base64UrlFingerprint:
+		return prefix + base64.URLEncoding.EncodeToString(sum[:])
+	case HexFingerprint:
+		return prefix + strings.ToLower(hex.EncodeToString(sum[:]))
+	case EmojiFingerprint:
+		return prefix + emoji.Emoji(sum[:])
 	default:
-		fp = fingerprint.Fingerprint(sum[:], encoding)
-	}
-	if fp == "" {
 		return ""
 	}
-	return "SHA256:" + fp
 }
 
 // FormatFingerprint parses a public key from an authorized_keys file used in
diff --git a/x509util/fingerprint.go b/x509util/fingerprint.go
deleted file mode 100644
index e75a6df..0000000
--- a/x509util/fingerprint.go
+++ /dev/null
@@ -1,48 +0,0 @@
-package x509util
-
-import (
-	"crypto/sha256"
-	"crypto/x509"
-
-	"go.step.sm/crypto/fingerprint"
-)
-
-// FingerprintEncoding defines the supported encodings in certificate
-// fingerprints.
-type FingerprintEncoding = fingerprint.Encoding
-
-// Supported fingerprint encodings.
-const (
-	// DefaultFingerprint represents the hex encoding of the fingerprint.
-	DefaultFingerprint = FingerprintEncoding(0)
-	// HexFingerprint represents the hex encoding of the fingerprint.
-	HexFingerprint = fingerprint.HexFingerprint
-	// Base64Fingerprint represents the base64 encoding of the fingerprint.
-	Base64Fingerprint = fingerprint.Base64Fingerprint
-	// Base64URLFingerprint represents the base64URL encoding of the fingerprint.
-	Base64URLFingerprint = fingerprint.Base64URLFingerprint
-	// Base64RawFingerprint represents the base64RawStd encoding of the fingerprint.
-	Base64RawFingerprint = fingerprint.Base64RawFingerprint
-	// Base64RawURLFingerprint represents the base64RawURL encoding of the fingerprint.
-	Base64RawURLFingerprint = fingerprint.Base64RawURLFingerprint
-	// EmojiFingerprint represents the emoji encoding of the fingerprint.
-	EmojiFingerprint = fingerprint.EmojiFingerprint
-)
-
-// Fingerprint returns the SHA-256 fingerprint of the certificate.
-func Fingerprint(cert *x509.Certificate) string {
-	return EncodedFingerprint(cert, DefaultFingerprint)
-}
-
-// EncodedFingerprint returns the SHA-256 hash of the certificate using the
-// specified encoding. If an invalid encoding is passed, the return value will
-// be an empty string.
-func EncodedFingerprint(cert *x509.Certificate, encoding FingerprintEncoding) string {
-	sum := sha256.Sum256(cert.Raw)
-	switch encoding {
-	case DefaultFingerprint:
-		return fingerprint.Fingerprint(sum[:], HexFingerprint)
-	default:
-		return fingerprint.Fingerprint(sum[:], encoding)
-	}
-}
diff --git a/x509util/utils.go b/x509util/utils.go
index b3961da..a8575d9 100644
--- a/x509util/utils.go
+++ b/x509util/utils.go
@@ -5,9 +5,12 @@ import (
 	"crypto"
 	"crypto/rand"
 	"crypto/sha1" //nolint:gosec // SubjectKeyIdentifier by RFC 5280
+	"crypto/sha256"
 	"crypto/x509"
 	"crypto/x509/pkix"
 	"encoding/asn1"
+	"encoding/base64"
+	"encoding/hex"
 	"math/big"
 	"net"
 	"net/url"
@@ -16,9 +19,31 @@ import (
 	"unicode/utf8"
 
 	"github.com/pkg/errors"
+	"go.step.sm/crypto/internal/emoji"
 	"golang.org/x/net/idna"
 )
 
+// FingerprintEncoding defines the supported encodings in certificate
+// fingerprints.
+type FingerprintEncoding int
+
+// Supported fingerprint encodings.
+const (
+	// HexFingerprint represents the hex encoding of the fingerprint. This is
+	// the default encoding for an X.509 certificate.
+	HexFingerprint FingerprintEncoding = iota
+	// Base64Fingerprint represents the base64 encoding of the fingerprint.
+	Base64Fingerprint
+	// Base64UrlFingerprint represents the base64URL encoding of the fingerprint.
+	Base64UrlFingerprint
+	// Base64RawFingerprint represents the base64RawStd encoding of the fingerprint.
+	Base64RawFingerprint
+	// Base64RawURLFingerprint represents the base64RawURL encoding of the fingerprint.
+	Base64RawURLFingerprint
+	// EmojiFingerprint represents the emoji encoding of the fingerprint.
+	EmojiFingerprint
+)
+
 var emptyASN1Subject = []byte{0x30, 0}
 
 // SanitizeName converts the given domain to its ASCII form.
@@ -88,6 +113,34 @@ func CreateSANs(sans []string) []SubjectAlternativeName {
 	return sanTypes
 }
 
+// Fingerprint returns the SHA-256 fingerprint of the certificate.
+func Fingerprint(cert *x509.Certificate) string {
+	return EncodedFingerprint(cert, HexFingerprint)
+}
+
+// EncodedFingerprint returns the SHA-256 hash of the certificate using the
+// specified encoding. If an invalid encoding is passed, the return value will
+// be an empty string.
+func EncodedFingerprint(cert *x509.Certificate, encoding FingerprintEncoding) string {
+	sum := sha256.Sum256(cert.Raw)
+	switch encoding {
+	case HexFingerprint:
+		return strings.ToLower(hex.EncodeToString(sum[:]))
+	case Base64Fingerprint:
+		return base64.StdEncoding.EncodeToString(sum[:])
+	case Base64UrlFingerprint:
+		return base64.URLEncoding.EncodeToString(sum[:])
+	case Base64RawFingerprint:
+		return base64.RawStdEncoding.EncodeToString(sum[:])
+	case Base64RawURLFingerprint:
+		return base64.RawURLEncoding.EncodeToString(sum[:])
+	case EmojiFingerprint:
+		return emoji.Emoji(sum[:])
+	default:
+		return ""
+	}
+}
+
 // generateSerialNumber returns a random serial number.
 func generateSerialNumber() (*big.Int, error) {
 	limit := new(big.Int).Lsh(big.NewInt(1), 128)


Test patch:
diff --git a/fingerprint/fingerprint_test.go b/fingerprint/fingerprint_test.go
deleted file mode 100644
index ac09c45..0000000
--- a/fingerprint/fingerprint_test.go
+++ /dev/null
@@ -1,87 +0,0 @@
-package fingerprint
-
-import (
-	"crypto"
-	"errors"
-	"hash"
-	"testing"
-)
-
-type failHash struct{}
-
-func (h failHash) Write(b []byte) (int, error) {
-	return 0, errors.New("failed to write")
-}
-func (h failHash) Sum(b []byte) []byte { return nil }
-func (h failHash) Reset()              {}
-func (h failHash) Size() int           { return 32 }
-func (h failHash) BlockSize() int      { return 32 }
-
-func TestNew(t *testing.T) {
-	data := []byte(`Lorem ipsum dolor sit amet`)
-	// This overwrites MD4 with failHash
-	crypto.RegisterHash(1, func() hash.Hash {
-		return failHash{}
-	})
-	type args struct {
-		data     []byte
-		h        crypto.Hash
-		encoding Encoding
-	}
-	tests := []struct {
-		name    string
-		args    args
-		want    string
-		wantErr bool
-	}{
-		{"sha256", args{data, crypto.SHA256, HexFingerprint}, "16aba5393ad72c0041f5600ad3c2c52ec437a2f0c7fc08fadfc3c0fe9641d7a3", false},
-		{"unavailable", args{data, crypto.Hash(1000), HexFingerprint}, "", true},
-		{"fail encoding", args{data, crypto.SHA256, Encoding(1000)}, "", true},
-		{"fail write", args{data, crypto.Hash(1), HexFingerprint}, "", true},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			got, err := New(tt.args.data, tt.args.h, tt.args.encoding)
-			if (err != nil) != tt.wantErr {
-				t.Errorf("New() error = %v, wantErr %v", err, tt.wantErr)
-				return
-			}
-			if got != tt.want {
-				t.Errorf("New() = %v, want %v", got, tt.want)
-			}
-		})
-	}
-}
-
-func TestFingerprint(t *testing.T) {
-	digest := []byte{
-		0x38, 0x01, 0x16, 0x21, 0xec, 0xdc, 0xc2, 0x17,
-		0x2e, 0x93, 0x3a, 0x1e, 0xf2, 0x31, 0x7e, 0xfc,
-		0x53, 0x5a, 0x16, 0x1c, 0x00, 0x33, 0x3a, 0xee,
-		0x3f, 0x84, 0xab, 0xfa, 0xb4, 0xe6, 0x40, 0xbf,
-	}
-	type args struct {
-		digest   []byte
-		encoding Encoding
-	}
-	tests := []struct {
-		name string
-		args args
-		want string
-	}{
-		{"HexFingerprint", args{digest, HexFingerprint}, "38011621ecdcc2172e933a1ef2317efc535a161c00333aee3f84abfab4e640bf"},
-		{"Base64Fingerprint", args{digest, Base64Fingerprint}, "OAEWIezcwhcukzoe8jF+/FNaFhwAMzruP4Sr+rTmQL8="},
-		{"Base64URLFingerprint", args{digest, Base64URLFingerprint}, "OAEWIezcwhcukzoe8jF-_FNaFhwAMzruP4Sr-rTmQL8="},
-		{"Base64RawFingerprint", args{digest, Base64RawFingerprint}, "OAEWIezcwhcukzoe8jF+/FNaFhwAMzruP4Sr+rTmQL8"},
-		{"Base64RawURLFingerprint", args{digest, Base64RawURLFingerprint}, "OAEWIezcwhcukzoe8jF-_FNaFhwAMzruP4Sr-rTmQL8"},
-		{"EmojiFingerprint", args{digest, EmojiFingerprint}, "💨🎱🌼📆🎠🎉🎿🚙🍪🌊♦️💡✌️🐮🔒❌🖕😬🌼👦👍👑♦️🇬🇧👂🔬📌♿🚀🚜🍆🐑"},
-		{"Unknown", args{digest, 0}, ""},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			if got := Fingerprint(tt.args.digest, tt.args.encoding); got != tt.want {
-				t.Errorf("Fingerprint() = %v, want %v", got, tt.want)
-			}
-		})
-	}
-}
diff --git a/sshutil/fingerprint_test.go b/sshutil/fingerprint_test.go
index f10394b..b344b4b 100644
--- a/sshutil/fingerprint_test.go
+++ b/sshutil/fingerprint_test.go
@@ -86,11 +86,11 @@ func TestEncodedFingerprint(t *testing.T) {
 		args args
 		want string
 	}{
-		{"default", args{sshECKey, 0}, ssh.FingerprintSHA256(sshECKey)},
+		{"ok", args{sshECKey, 0}, ssh.FingerprintSHA256(sshECKey)},
 		{"Base64RawFingerprint", args{sshECKey, Base64RawFingerprint}, expected},
 		{"Base64RawURLFingerprint", args{sshECKey, Base64RawURLFingerprint}, "SHA256:" + base64.RawURLEncoding.EncodeToString(b)},
 		{"Base64Fingerprint", args{sshECKey, Base64Fingerprint}, "SHA256:" + base64.StdEncoding.EncodeToString(b)},
-		{"Base64URLFingerprint", args{sshECKey, Base64URLFingerprint}, "SHA256:" + base64.URLEncoding.EncodeToString(b)},
+		{"Base64UrlFingerprint", args{sshECKey, Base64UrlFingerprint}, "SHA256:" + base64.URLEncoding.EncodeToString(b)},
 		{"HexFingerprint", args{sshECKey, HexFingerprint}, "SHA256:" + hex.EncodeToString(b)},
 		{"EmojiFingerprint", args{sshECKey, EmojiFingerprint}, "SHA256:" + emoji.Emoji(b)},
 		{"fail", args{sshECKey, 100}, ""},
@@ -169,7 +169,7 @@ func TestFormatFingerprint(t *testing.T) {
 		{"Base64RawFingerprint", args{marshal(sshECKey, ""), Base64RawFingerprint}, "256 " + ssh.FingerprintSHA256(sshECKey) + " no comment (ECDSA)", false},
 		{"Base64RawURLFingerprint", args{marshal(sshECKey, ""), Base64RawURLFingerprint}, "256 SHA256:" + base64.RawURLEncoding.EncodeToString(ec256Bytes) + " no comment (ECDSA)", false},
 		{"Base64Fingerprint", args{marshal(sshECKey, ""), Base64Fingerprint}, "256 SHA256:" + base64.StdEncoding.EncodeToString(ec256Bytes) + " no comment (ECDSA)", false},
-		{"Base64UrlFingerprint", args{marshal(sshECKey, ""), Base64URLFingerprint}, "256 SHA256:" + base64.URLEncoding.EncodeToString(ec256Bytes) + " no comment (ECDSA)", false},
+		{"Base64UrlFingerprint", args{marshal(sshECKey, ""), Base64UrlFingerprint}, "256 SHA256:" + base64.URLEncoding.EncodeToString(ec256Bytes) + " no comment (ECDSA)", false},
 		{"HexFingerprint", args{marshal(sshECKey, ""), HexFingerprint}, "256 SHA256:" + hex.EncodeToString(ec256Bytes) + " no comment (ECDSA)", false},
 		{"EmojiFingerprint", args{marshal(sshECKey, ""), EmojiFingerprint}, "256 SHA256:" + emoji.Emoji(ec256Bytes) + " no comment (ECDSA)", false},
 		{"fail input", args{marshal(sshECKey, "")[:50], EmojiFingerprint}, "", true},
diff --git a/x509util/fingerprint_test.go b/x509util/fingerprint_test.go
deleted file mode 100644
index 3126e99..0000000
--- a/x509util/fingerprint_test.go
+++ /dev/null
@@ -1,62 +0,0 @@
-package x509util
-
-import (
-	"crypto/x509"
-	"testing"
-)
-
-func TestFingerprint(t *testing.T) {
-	ecdsaCrt := decodeCertificateFile(t, "testdata/google.crt")
-	rsaCrt := decodeCertificateFile(t, "testdata/smallstep.crt")
-	ed25519Crt := decodeCertificateFile(t, "testdata/ed25519.crt")
-
-	type args struct {
-		cert *x509.Certificate
-	}
-	tests := []struct {
-		name string
-		args args
-		want string
-	}{
-		{"ecdsaCert", args{ecdsaCrt}, "38011621ecdcc2172e933a1ef2317efc535a161c00333aee3f84abfab4e640bf"},
-		{"rsaCert", args{rsaCrt}, "5eeaf6dd1d1f064f6f95c5d74c39ad0abca33bdba59d2844d0b5e6d8453f6c4b"},
-		{"ed25519Cert", args{ed25519Crt}, "047b2fff20997a5009d1b36864af95b03f168c09dc2ed1a71ee36ccf973c9d31"},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			if got := Fingerprint(tt.args.cert); got != tt.want {
-				t.Errorf("Fingerprint() = %v, want %v", got, tt.want)
-			}
-		})
-	}
-}
-
-func TestEncodedFingerprint(t *testing.T) {
-	ecdsaCrt := decodeCertificateFile(t, "testdata/google.crt")
-
-	type args struct {
-		cert     *x509.Certificate
-		encoding FingerprintEncoding
-	}
-	tests := []struct {
-		name string
-		args args
-		want string
-	}{
-		{"default", args{ecdsaCrt, 0}, "38011621ecdcc2172e933a1ef2317efc535a161c00333aee3f84abfab4e640bf"},
-		{"HexFingerprint", args{ecdsaCrt, HexFingerprint}, "38011621ecdcc2172e933a1ef2317efc535a161c00333aee3f84abfab4e640bf"},
-		{"Base64Fingerprint", args{ecdsaCrt, Base64Fingerprint}, "OAEWIezcwhcukzoe8jF+/FNaFhwAMzruP4Sr+rTmQL8="},
-		{"Base64URLFingerprint", args{ecdsaCrt, Base64URLFingerprint}, "OAEWIezcwhcukzoe8jF-_FNaFhwAMzruP4Sr-rTmQL8="},
-		{"Base64RawFingerprint", args{ecdsaCrt, Base64RawFingerprint}, "OAEWIezcwhcukzoe8jF+/FNaFhwAMzruP4Sr+rTmQL8"},
-		{"Base64RawURLFingerprint", args{ecdsaCrt, Base64RawURLFingerprint}, "OAEWIezcwhcukzoe8jF-_FNaFhwAMzruP4Sr-rTmQL8"},
-		{"EmojiFingerprint", args{ecdsaCrt, EmojiFingerprint}, "💨🎱🌼📆🎠🎉🎿🚙🍪🌊♦️💡✌️🐮🔒❌🖕😬🌼👦👍👑♦️🇬🇧👂🔬📌♿🚀🚜🍆🐑"},
-		{"Unknown", args{ecdsaCrt, 100}, ""},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			if got := EncodedFingerprint(tt.args.cert, tt.args.encoding); got != tt.want {
-				t.Errorf("EncodedFingerprint() = %v, want %v", got, tt.want)
-			}
-		})
-	}
-}
diff --git a/x509util/utils_test.go b/x509util/utils_test.go
index 534b884..b05e052 100644
--- a/x509util/utils_test.go
+++ b/x509util/utils_test.go
@@ -143,6 +143,61 @@ func TestCreateSANs(t *testing.T) {
 	}
 }
 
+func TestFingerprint(t *testing.T) {
+	ecdsaCrt := decodeCertificateFile(t, "testdata/google.crt")
+	rsaCrt := decodeCertificateFile(t, "testdata/smallstep.crt")
+	ed25519Crt := decodeCertificateFile(t, "testdata/ed25519.crt")
+
+	type args struct {
+		cert *x509.Certificate
+	}
+	tests := []struct {
+		name string
+		args args
+		want string
+	}{
+		{"ecdsaCert", args{ecdsaCrt}, "38011621ecdcc2172e933a1ef2317efc535a161c00333aee3f84abfab4e640bf"},
+		{"rsaCert", args{rsaCrt}, "5eeaf6dd1d1f064f6f95c5d74c39ad0abca33bdba59d2844d0b5e6d8453f6c4b"},
+		{"ed25519Cert", args{ed25519Crt}, "047b2fff20997a5009d1b36864af95b03f168c09dc2ed1a71ee36ccf973c9d31"},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := Fingerprint(tt.args.cert); got != tt.want {
+				t.Errorf("Fingerprint() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestEncodedFingerprint(t *testing.T) {
+	ecdsaCrt := decodeCertificateFile(t, "testdata/google.crt")
+
+	type args struct {
+		cert     *x509.Certificate
+		encoding FingerprintEncoding
+	}
+	tests := []struct {
+		name string
+		args args
+		want string
+	}{
+		{"HexFingerprint", args{ecdsaCrt, HexFingerprint}, "38011621ecdcc2172e933a1ef2317efc535a161c00333aee3f84abfab4e640bf"},
+		{"Base64Fingerprint", args{ecdsaCrt, Base64Fingerprint}, "OAEWIezcwhcukzoe8jF+/FNaFhwAMzruP4Sr+rTmQL8="},
+		{"Base64UrlFingerprint", args{ecdsaCrt, Base64UrlFingerprint}, "OAEWIezcwhcukzoe8jF-_FNaFhwAMzruP4Sr-rTmQL8="},
+		{"Base64RawFingerprint", args{ecdsaCrt, Base64RawFingerprint}, "OAEWIezcwhcukzoe8jF+/FNaFhwAMzruP4Sr+rTmQL8"},
+		{"Base64RawURLFingerprint", args{ecdsaCrt, Base64RawURLFingerprint}, "OAEWIezcwhcukzoe8jF-_FNaFhwAMzruP4Sr-rTmQL8"},
+		{"EmojiFingerprint", args{ecdsaCrt, EmojiFingerprint}, "💨🎱🌼📆🎠🎉🎿🚙🍪🌊♦️💡✌️🐮🔒❌🖕😬🌼👦👍👑♦️🇬🇧👂🔬📌♿🚀🚜🍆🐑"},
+		{"Unknown", args{ecdsaCrt, 100}, ""},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := EncodedFingerprint(tt.args.cert, tt.args.encoding); got != tt.want {
+				t.Errorf("EncodedFingerprint() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
 func Test_generateSubjectKeyID(t *testing.T) {
 	ecdsaCrt := decodeCertificateFile(t, "testdata/google.crt")
 	rsaCrt := decodeCertificateFile(t, "testdata/smallstep.crt")