Compare commits

..
10 Commits
Author SHA1 Message Date
Gopher Robot cdce021fa6 go.mod: update golang.org/x dependencies
Update golang.org/x dependencies to their latest tagged versions.

Change-Id: I431b878ec8830bf1894ae19176b5984b00954557
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/798280
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Auto-Submit: Gopher Robot <gobot@golang.org>
2026-07-08 11:22:26 -07:00
Roland Shoemaker d9474cc485 openpgp: make the deprecation message more explicit
The package is unmaintained, unsafe at any speed, and does not receive
security fixes. Document that, and point at the ProtonMail fork for
those that _must_ still use OpenPGP.

Change-Id: Ia602eaaf9e08bd25389400ebe7f346b60bdb9d99
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/794200
Auto-Submit: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Damien Neil <dneil@google.com>
2026-07-07 10:06:58 -07:00
Nicola Murino 7626c50256 ssh: verify declared key type matches decoded key in authorized_keys
ParseAuthorizedKey and ParseKnownHosts previously ignored the key type
field (e.g. "ssh-rsa") in each entry, relying solely on the type
information embedded within the base64-encoded key blob.

For ParseAuthorizedKey this also caused a single-token option to be
silently dropped: a line such as "restrict <key>" (with the key type
omitted) was parsed as an unrestricted key, because the option token
landed in the key type position and was discarded together with its
meaning. The same happens for no-pty, no-port-forwarding and the other
single-word options. OpenSSH's sshkey_read rejects such lines outright,
as the option token cannot be read as a key type.

OpenSSH's sshkey_read also explicitly verifies that the key type
declared in the text matches the type of the parsed key, returning
SSH_ERR_KEY_TYPE_MISMATCH if they differ.

This change adds, in both functions, a check that the declared key type
matches the decoded key's type, returning an error for malformed lines
where they diverge. This mirrors the fix already applied to the
ssh/knownhosts package in CL 782427.

Change-Id: I9163108d964de4be8a415fe0efd68e6b71f77990
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/792840
Reviewed-by: Filippo Valsorda <filippo@golang.org>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Nicola Murino <nicola.murino@gmail.com>
Reviewed-by: Neal Patel <nealpatel@google.com>
Reviewed-by: Junyang Shao <shaojunyang@google.com>
2026-06-30 10:24:32 -07:00
Nicola Murino 0471e7969e ssh/agent: enforce strict limits on DSA key parameters
The parseDSAKey function constructed a *dsa.PrivateKey directly from the
add-identity request without validating the key parameters. Unlike DSA
certificates, whose parameters are checked by the ssh package when the
certificate's public key is parsed, raw DSA keys added to the agent were
not validated at all.

Align the raw DSA key parsing with the validation already performed by
the main ssh package.

Fixes golang/go#79725

Change-Id: I537cc2175d35c19848c90c68739cf94ba7b50e10
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/795422
Reviewed-by: Roland Shoemaker <roland@golang.org>
Reviewed-by: Junyang Shao <shaojunyang@google.com>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2026-06-30 10:06:28 -07:00
Neal Patel 6435c37ab6 ssh: sanitize client disconnect messages
A malicious peer can send control characters
and escape sequences in SSH_MSG_DISCONNECT;
strip these characters and %q escape it.

Change-Id: I266f78630a7a816a79ce4dda568ce57d7c3f6fb0
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/780180
Commit-Queue: Nicola Murino <nicola.murino@gmail.com>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Neal Patel <nealpatel@google.com>
Reviewed-by: Nicola Murino <nicola.murino@gmail.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Auto-Submit: Nicola Murino <nicola.murino@gmail.com>
2026-06-29 10:23:17 -07:00
Nicola Murino 7d695da948 ssh/agent: drain channel stderr in agent forwarders
ForwardToAgent and ForwardToRemote only read the main stream of the
auth-agent@openssh.com channels they accept. If a peer sends data on
the channel's extended (stderr) stream the bytes accumulate in the
client-side extPending buffer and the receive window is never
replenished, because the window is only adjusted as a side effect of
ReadExtended. That can pin up to channelWindowSize (2 MiB) of memory
per channel and silently stalls any stderr traffic once the window is
exhausted.

The auth-agent protocol does not use stderr, so a well-behaved peer
never sends anything on it. To stay tolerant of misbehaving peers
without leaving the channel half-stuck, drain the stderr stream into
io.Discard, mirroring the existing DiscardRequests pattern. The
goroutine exits when the channel is closed because Stderr().Read
returns io.EOF.

Add a regression test that opens an agent-forwarding channel and
writes more than the default window on the stderr stream from the
server side. Without the fix the write blocks once the remote window
is exhausted; with the fix the bytes are drained and the agent stream
remains usable.

Change-Id: Iadf8ea6ca726c058421bbc39f92e0100579fda17
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/783720
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Carlos Amedee <carlos@golang.org>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
2026-06-29 06:36:26 -07:00
Daniel McCarney 5b7f841599 acme/autocert: fix data race in Manager.createCert
Previously Manager.createCert() read state.locked without holding any
lock, while the owner goroutine wrote state.locked = false under the
state's write lock. Concurrent goroutines for the same domain raced on
that field.

We fix the issue by removing the certState.locked field and instead
having Manager.certState() return an additional owner bool computed
under the m.stateMu lock. This allows the Manager.createCert() caller to
know whether it must block on the read lock and return the state handled
by another goroutine, or instead do the work itself and release the
write lock.

A regression unit test is included that fails under -race without the
fix, and passes with the fix in-place.

Fixes golang/go#80119

Change-Id: I0f4c5c98f7e6bcf1ab71a3c0707bb0c7ce73415b
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/793840
Reviewed-by: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
Auto-Submit: Daniel McCarney <daniel@binaryparadox.net>
2026-06-26 08:59:20 -07:00
harjoth 0b316e7ee4 argon2: update RFC 9106 parameter recommendations
Update the IDKey example to use RFC 9106's first recommended Argon2id
option and clarify the relationship between the first and second
recommended options.

Fixes golang/go#79823

Change-Id: If44a86a5a8112b02fab97b4d5e325fe91d6049ee
GitHub-Last-Rev: a764ae65875f12d7422865c4e83f345a8a4f246e
GitHub-Pull-Request: golang/crypto#357
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/789020
Reviewed-by: Roland Shoemaker <roland@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2026-06-18 09:22:19 -07:00
Gopher Robot 55aec0a86b x509roots/fallback: update bundle
This is an automated CL which updates the NSS root bundle.

[git-generate]
go generate ./x509roots

Change-Id: I448f9962a67bf042b04a2e34f16ae02a004d6edd
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/791040
Auto-Submit: Gopher Robot <gobot@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
2026-06-15 14:38:55 -07:00
Daniel McCarney 5f2de1a9f1 internal: remove wycheproof tests
Equivalent coverage using newer Wycheproof vectors has been added to the
standard library, alongside the implementations under test.

In the case where the algorithm doesn't exist in the stdlib, but is
intended to be supported there one day (e.g. chacha20poly1305) we flip
the relationship and run the Wycheproof tests from the stdlib on the
vendored /x/crypto. As a result the legacy Wycheproof coverage in this
repo can be removed.

Change-Id: Ic07d559e42599b715906f5bcc39be10944a8dde4
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/758420
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Auto-Submit: Daniel McCarney <daniel@binaryparadox.net>
Reviewed-by: Roland Shoemaker <roland@golang.org>
2026-06-09 11:23:32 -07:00
37 changed files with 533 additions and 1985 deletions
+21 -23
View File
@@ -564,24 +564,21 @@ func encodeECDSAKey(w io.Writer, key *ecdsa.PrivateKey) error {
// If the domain is already being verified, it waits for the existing verification to complete.
// Either way, createCert blocks for the duration of the whole process.
func (m *Manager) createCert(ctx context.Context, ck certKey) (*tls.Certificate, error) {
// TODO: maybe rewrite this whole piece using sync.Once
state, err := m.certState(ck)
state, owner, err := m.certState(ck)
if err != nil {
return nil, err
}
// state may exist if another goroutine is already working on it
// in which case just wait for it to finish
if !state.locked {
// If another goroutine is already working on this state, wait for it
// to finish by taking the read lock
if !owner {
state.RLock()
defer state.RUnlock()
return state.tlscert()
}
// We are the first; state is locked.
// Unblock the readers when domain ownership is verified
// and we got the cert or the process failed.
// We are the first to work on this certKey, so state is write-locked.
// Unblock the readers when our work is complete.
defer state.Unlock()
state.locked = false
der, leaf, err := m.authorizedCert(ctx, state.key, ck)
if err != nil {
@@ -611,10 +608,15 @@ func (m *Manager) createCert(ctx context.Context, ck certKey) (*tls.Certificate,
return state.tlscert()
}
// certState returns a new or existing certState.
// If a new certState is returned, state.exist is false and the state is locked.
// certState returns a new or existing certState along with a boolean
// indicating whether the caller is the owner of the state.
//
// The owner of the state is responsible for performing the ACME work and
// must unlock the state's write lock when done. Non-owner callers should
// wait on the state's read lock for the owner to finish.
//
// The returned error is non-nil only in the case where a new state could not be created.
func (m *Manager) certState(ck certKey) (*certState, error) {
func (m *Manager) certState(ck certKey) (*certState, bool, error) {
m.stateMu.Lock()
defer m.stateMu.Unlock()
if m.state == nil {
@@ -622,7 +624,7 @@ func (m *Manager) certState(ck certKey) (*certState, error) {
}
// existing state
if state, ok := m.state[ck]; ok {
return state, nil
return state, false, nil
}
// new locked state
@@ -636,16 +638,13 @@ func (m *Manager) certState(ck certKey) (*certState, error) {
key, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
}
if err != nil {
return nil, err
return nil, false, err
}
state := &certState{
key: key,
locked: true,
}
state := &certState{key: key}
state.Lock() // will be unlocked by m.certState caller
m.state[ck] = state
return state, nil
return state, true, nil
}
// authorizedCert starts the domain ownership verification process and requests a new cert upon success.
@@ -1035,10 +1034,9 @@ func (m *Manager) now() time.Time {
// certState is ready when its mutex is unlocked for reading.
type certState struct {
sync.RWMutex
locked bool // locked for read/write
key crypto.Signer // private key for cert
cert [][]byte // DER encoding
leaf *x509.Certificate // parsed cert[0]; always non-nil if cert != nil
key crypto.Signer // private key for cert
cert [][]byte // DER encoding
leaf *x509.Certificate // parsed cert[0]; always non-nil if cert != nil
}
// tlscert creates a tls.Certificate from s.key and s.cert.
+27
View File
@@ -513,6 +513,33 @@ func TestGetCertificate_failedAttempt(t *testing.T) {
}
}
// TestGetCertificate_concurrent guards against a data race on certState
// fields between the goroutine performing the ACME work for a domain and
// the other goroutines waiting on the result. See golang/go#80119.
func TestGetCertificate_concurrent(t *testing.T) {
// An unreachable directory URL makes the owner goroutine fail
// quickly inside createCert, so its writes overlap with the
// non-owner goroutines reaching the same code path.
m := &Manager{
Prompt: AcceptTOS,
Client: &acme.Client{DirectoryURL: "http://127.0.0.1:1/"},
}
defer m.stopRenew()
start := make(chan struct{})
var wg sync.WaitGroup
for i := 0; i < 64; i++ {
wg.Add(1)
go func() {
defer wg.Done()
<-start
m.GetCertificate(clientHelloInfo(exampleDomain, algECDSA))
}()
}
close(start)
wg.Wait()
}
func TestRevokeFailedAuthz(t *testing.T) {
ca := acmetest.NewCAServer(t)
// Make the authz unfulfillable on the client side, so it will be left
+18 -17
View File
@@ -17,8 +17,8 @@
// It uses data-independent memory access, which is preferred for password
// hashing and password-based key derivation. Argon2i requires more passes over
// memory than Argon2id to protect from trade-off attacks. The recommended
// parameters (taken from [RFC 9106 Section 7.3]) for non-interactive operations are time=3 and to
// use the maximum available memory.
// parameters (taken from [RFC 9106 Section 7.3]) for non-interactive
// operations are time=3 and to use the maximum available memory.
//
// # Argon2id
//
@@ -26,11 +26,14 @@
// Argon2i and Argon2d. It uses data-independent memory access for the first
// half of the first iteration over the memory and data-dependent memory access
// for the rest. Argon2id is side-channel resistant and provides better brute-
// force cost savings due to time-memory tradeoffs than Argon2i. The recommended
// parameters for non-interactive operations (taken from [RFC 9106 Section 7.3]) are time=1 and to
// use the maximum available memory.
// force cost savings due to time-memory tradeoffs than Argon2i. [RFC 9106
// Section 4] recommends time=1, memory=2*1024*1024 KiB (2 GiB), and threads=4
// as the first recommended option. If much less memory is available, it
// recommends time=3, memory=64*1024 KiB (64 MiB), and threads=4 as the second
// recommended option.
//
// [argon2-specs.pdf]: https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.pdf
// [RFC 9106 Section 4]: https://www.rfc-editor.org/rfc/rfc9106.html#section-4
// [RFC 9106 Section 7.3]: https://www.rfc-editor.org/rfc/rfc9106.html#section-7.3
package argon2
@@ -59,9 +62,9 @@ const (
//
// key := argon2.Key([]byte("some password"), salt, 3, 32*1024, 4, 32)
//
// [RFC 9106 Section 7.3] recommends time=3, and memory=32*1024 as a sensible number.
// If using that amount of memory (32 MB) is not possible in some contexts then
// the time parameter can be increased to compensate.
// The example above uses time=3 and memory=32*1024. Argon2i generally
// requires more passes over memory than Argon2id. If in doubt, prefer IDKey
// and its Argon2id parameter recommendations.
//
// The time parameter specifies the number of passes over the memory and the
// memory parameter specifies the size of the memory in KiB. For example
@@ -69,8 +72,6 @@ const (
// adjusted to the number of available CPUs. The cost parameters should be
// increased as memory latency and CPU parallelism increases. Remember to get a
// good random salt.
//
// [RFC 9106 Section 7.3]: https://www.rfc-editor.org/rfc/rfc9106.html#section-7.3
func Key(password, salt []byte, time, memory uint32, threads uint8, keyLen uint32) []byte {
return deriveKey(argon2i, password, salt, nil, nil, time, memory, threads, keyLen)
}
@@ -83,20 +84,20 @@ func Key(password, salt []byte, time, memory uint32, threads uint8, keyLen uint3
// For example, you can get a derived key for e.g. AES-256 (which needs a
// 32-byte key) by doing:
//
// key := argon2.IDKey([]byte("some password"), salt, 1, 64*1024, 4, 32)
// key := argon2.IDKey([]byte("some password"), salt, 1, 2*1024*1024, 4, 32)
//
// [RFC 9106 Section 7.3] recommends time=1, and memory=64*1024 as a sensible number.
// If using that amount of memory (64 MB) is not possible in some contexts then
// the time parameter can be increased to compensate.
// The example above uses the first [RFC 9106 Section 4] recommended option.
// If much less memory is available, the second recommended option is time=3,
// memory=64*1024 KiB (64 MiB), and threads=4.
//
// The time parameter specifies the number of passes over the memory and the
// memory parameter specifies the size of the memory in KiB. For example
// memory=64*1024 sets the memory cost to ~64 MB. The number of threads can be
// adjusted to the numbers of available CPUs. The cost parameters should be
// memory=2*1024*1024 sets the memory cost to ~2 GiB. The number of threads can
// be adjusted to the numbers of available CPUs. The cost parameters should be
// increased as memory latency and CPU parallelism increases. Remember to get a
// good random salt.
//
// [RFC 9106 Section 7.3]: https://www.rfc-editor.org/rfc/rfc9106.html#section-7.3
// [RFC 9106 Section 4]: https://www.rfc-editor.org/rfc/rfc9106.html#section-4
func IDKey(password, salt []byte, time, memory uint32, threads uint8, keyLen uint32) []byte {
return deriveKey(argon2id, password, salt, nil, nil, time, memory, threads, keyLen)
}
+4 -4
View File
@@ -3,9 +3,9 @@ module golang.org/x/crypto
go 1.25.0
require (
golang.org/x/net v0.55.0 // tagx:ignore
golang.org/x/sys v0.46.0
golang.org/x/term v0.44.0
golang.org/x/net v0.56.0 // tagx:ignore
golang.org/x/sys v0.47.0
golang.org/x/term v0.45.0
)
require golang.org/x/text v0.38.0 // indirect
require golang.org/x/text v0.40.0 // indirect
+8 -8
View File
@@ -1,8 +1,8 @@
golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8=
golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww=
golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc=
golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y=
golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE=
golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4=
golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0=
golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w=
golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs=
golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY=
-12
View File
@@ -1,12 +0,0 @@
This package runs a set of the Wycheproof tests provided by
https://github.com/google/wycheproof.
The JSON test files live in
https://github.com/google/wycheproof/tree/master/testvectors
and are being fetched and cached at a pinned version every time
these tests are run. To change the version of the wycheproof
repository that is being used for testing, update wycheproofModVer.
The structs for these tests are generated from the
schemas provided in https://github.com/google/wycheproof/tree/master/schemas
using https://github.com/a-h/generate.
-176
View File
@@ -1,176 +0,0 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package wycheproof
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"fmt"
"testing"
"golang.org/x/crypto/chacha20poly1305"
)
func TestAEAD(t *testing.T) {
// AeadTestVector
type AeadTestVector struct {
// additional authenticated data
Aad string `json:"aad,omitempty"`
// A brief description of the test case
Comment string `json:"comment,omitempty"`
// the ciphertext (without iv and tag)
Ct string `json:"ct,omitempty"`
// A list of flags
Flags []string `json:"flags,omitempty"`
// the nonce
Iv string `json:"iv,omitempty"`
// the key
Key string `json:"key,omitempty"`
// the plaintext
Msg string `json:"msg,omitempty"`
// Test result
Result string `json:"result,omitempty"`
// the authentication tag
Tag string `json:"tag,omitempty"`
// Identifier of the test case
TcId int `json:"tcId,omitempty"`
}
// Notes a description of the labels used in the test vectors
type Notes struct {
}
// AeadTestGroup
type AeadTestGroup struct {
// the IV size in bits
IvSize int `json:"ivSize,omitempty"`
// the keySize in bits
KeySize int `json:"keySize,omitempty"`
// the expected size of the tag in bits
TagSize int `json:"tagSize,omitempty"`
Tests []*AeadTestVector `json:"tests,omitempty"`
Type interface{} `json:"type,omitempty"`
}
// Root
type Root struct {
// the primitive tested in the test file
Algorithm string `json:"algorithm,omitempty"`
// the version of the test vectors.
GeneratorVersion string `json:"generatorVersion,omitempty"`
// additional documentation
Header []string `json:"header,omitempty"`
// a description of the labels used in the test vectors
Notes *Notes `json:"notes,omitempty"`
// the number of test vectors in this test
NumberOfTests int `json:"numberOfTests,omitempty"`
Schema interface{} `json:"schema,omitempty"`
TestGroups []*AeadTestGroup `json:"testGroups,omitempty"`
}
testSealOpen := func(t *testing.T, aead cipher.AEAD, tv *AeadTestVector, recoverBadNonce func()) {
defer recoverBadNonce()
iv, tag, ct, msg, aad := decodeHex(tv.Iv), decodeHex(tv.Tag), decodeHex(tv.Ct), decodeHex(tv.Msg), decodeHex(tv.Aad)
genCT := aead.Seal(nil, iv, msg, aad)
genMsg, err := aead.Open(nil, iv, genCT, aad)
if err != nil {
t.Errorf("failed to decrypt generated ciphertext: %s", err)
}
if !bytes.Equal(genMsg, msg) {
t.Errorf("unexpected roundtripped plaintext: got %x, want %x", genMsg, msg)
}
ctWithTag := append(ct, tag...)
msg2, err := aead.Open(nil, iv, ctWithTag, aad)
wantPass := shouldPass(tv.Result, tv.Flags, nil)
if !wantPass && err == nil {
t.Error("decryption succeeded when it should've failed")
} else if wantPass {
if err != nil {
t.Fatalf("decryption failed: %s", err)
}
if !bytes.Equal(genCT, ctWithTag) {
t.Errorf("generated ciphertext doesn't match expected: got %x, want %x", genCT, ctWithTag)
}
if !bytes.Equal(msg, msg2) {
t.Errorf("decrypted ciphertext doesn't match expected: got %x, want %x", msg2, msg)
}
}
}
vectors := map[string]func(*testing.T, []byte) cipher.AEAD{
"aes_gcm_test.json": func(t *testing.T, key []byte) cipher.AEAD {
aesCipher, err := aes.NewCipher(key)
if err != nil {
t.Fatalf("failed to construct cipher: %s", err)
}
aead, err := cipher.NewGCM(aesCipher)
if err != nil {
t.Fatalf("failed to construct cipher: %s", err)
}
return aead
},
"chacha20_poly1305_test.json": func(t *testing.T, key []byte) cipher.AEAD {
aead, err := chacha20poly1305.New(key)
if err != nil {
t.Fatalf("failed to construct cipher: %s", err)
}
return aead
},
"xchacha20_poly1305_test.json": func(t *testing.T, key []byte) cipher.AEAD {
aead, err := chacha20poly1305.NewX(key)
if err != nil {
t.Fatalf("failed to construct cipher: %s", err)
}
return aead
},
}
for file, cipherInit := range vectors {
var root Root
readTestVector(t, file, &root)
for _, tg := range root.TestGroups {
for _, tv := range tg.Tests {
testName := fmt.Sprintf("%s #%d", file, tv.TcId)
if tv.Comment != "" {
testName += fmt.Sprintf(" %s", tv.Comment)
}
t.Run(testName, func(t *testing.T) {
aead := cipherInit(t, decodeHex(tv.Key))
testSealOpen(t, aead, tv, func() {
// A bad nonce causes a panic in AEAD.Seal and AEAD.Open,
// so should be recovered. Fail the test if it broke for
// some other reason.
if r := recover(); r != nil {
if tg.IvSize/8 == aead.NonceSize() {
t.Error("unexpected panic")
}
}
})
})
}
}
}
}
-127
View File
@@ -1,127 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package wycheproof
import (
"crypto/aes"
"crypto/cipher"
"encoding/hex"
"fmt"
"testing"
)
func TestAesCbc(t *testing.T) {
// IndCpaTestVector
type IndCpaTestVector struct {
// A brief description of the test case
Comment string `json:"comment,omitempty"`
// the raw ciphertext (without IV)
Ct string `json:"ct,omitempty"`
// A list of flags
Flags []string `json:"flags,omitempty"`
// the initialization vector
Iv string `json:"iv,omitempty"`
// the key
Key string `json:"key,omitempty"`
// the plaintext
Msg string `json:"msg,omitempty"`
// Test result
Result string `json:"result,omitempty"`
// Identifier of the test case
TcId int `json:"tcId,omitempty"`
}
// Notes a description of the labels used in the test vectors
type Notes struct {
}
// IndCpaTestGroup
type IndCpaTestGroup struct {
// the IV size in bits
IvSize int `json:"ivSize,omitempty"`
// the keySize in bits
KeySize int `json:"keySize,omitempty"`
// the expected size of the tag in bits
TagSize int `json:"tagSize,omitempty"`
Tests []*IndCpaTestVector `json:"tests,omitempty"`
Type interface{} `json:"type,omitempty"`
}
// Root
type Root struct {
// the primitive tested in the test file
Algorithm string `json:"algorithm,omitempty"`
// the version of the test vectors.
GeneratorVersion string `json:"generatorVersion,omitempty"`
// additional documentation
Header []string `json:"header,omitempty"`
// a description of the labels used in the test vectors
Notes *Notes `json:"notes,omitempty"`
// the number of test vectors in this test
NumberOfTests int `json:"numberOfTests,omitempty"`
Schema interface{} `json:"schema,omitempty"`
TestGroups []*IndCpaTestGroup `json:"testGroups,omitempty"`
}
var root Root
readTestVector(t, "aes_cbc_pkcs5_test.json", &root)
for _, tg := range root.TestGroups {
tests:
for _, tv := range tg.Tests {
block, err := aes.NewCipher(decodeHex(tv.Key))
if err != nil {
t.Fatalf("#%d: %v", tv.TcId, err)
}
mode := cipher.NewCBCDecrypter(block, decodeHex(tv.Iv))
ct := decodeHex(tv.Ct)
if len(ct)%aes.BlockSize != 0 {
panic(fmt.Sprintf("#%d: ciphertext is not a multiple of the block size", tv.TcId))
}
mode.CryptBlocks(ct, ct) // decrypt the block in place
// Skip the tests that are broken due to bad padding. Panic if there are any
// tests left that are invalid for some other reason in the future, to
// evaluate what to do with those tests.
for _, flag := range tv.Flags {
if flag == "BadPadding" {
continue tests
}
}
if !shouldPass(tv.Result, tv.Flags, nil) {
panic(fmt.Sprintf("#%d: found an invalid test that is broken for some reason other than bad padding", tv.TcId))
}
// Remove the PKCS#5 padding from the given ciphertext to validate it
padding := ct[len(ct)-1]
paddingNum := int(padding)
for i := paddingNum; i > 0; i-- {
if ct[len(ct)-i] != padding { // panic if the padding is unexpectedly bad
panic(fmt.Sprintf("#%d: bad padding at index=%d of %v", tv.TcId, i, ct))
}
}
ct = ct[:len(ct)-paddingNum]
if got, want := hex.EncodeToString(ct), tv.Msg; got != want {
t.Errorf("#%d, type: %s, comment: %q, decoded ciphertext not equal: %s, want %s", tv.TcId, tv.Result, tv.Comment, got, want)
}
}
}
}
-9
View File
@@ -1,9 +0,0 @@
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build boringcrypto
package wycheproof
const boringcryptoEnabled = true
-123
View File
@@ -1,123 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package wycheproof
import (
"crypto/dsa"
"testing"
wdsa "golang.org/x/crypto/internal/wycheproof/internal/dsa"
)
func TestDsa(t *testing.T) {
// AsnSignatureTestVector
type AsnSignatureTestVector struct {
// A brief description of the test case
Comment string `json:"comment,omitempty"`
// A list of flags
Flags []string `json:"flags,omitempty"`
// The message to sign
Msg string `json:"msg,omitempty"`
// Test result
Result string `json:"result,omitempty"`
// An ASN encoded signature for msg
Sig string `json:"sig,omitempty"`
// Identifier of the test case
TcId int `json:"tcId,omitempty"`
}
// DsaPublicKey
type DsaPublicKey struct {
// the generator of the multiplicative subgroup
G string `json:"g,omitempty"`
// the key size in bits
KeySize int `json:"keySize,omitempty"`
// the modulus p
P string `json:"p,omitempty"`
// the order of the generator g
Q string `json:"q,omitempty"`
// the key type
Type string `json:"type,omitempty"`
// the public key value
Y string `json:"y,omitempty"`
}
// DsaTestGroup
type DsaTestGroup struct {
// unenocded DSA public key
Key *DsaPublicKey `json:"key,omitempty"`
// DER encoded public key
KeyDer string `json:"keyDer,omitempty"`
// Pem encoded public key
KeyPem string `json:"keyPem,omitempty"`
// the hash function used for DSA
Sha string `json:"sha,omitempty"`
Tests []*AsnSignatureTestVector `json:"tests,omitempty"`
Type interface{} `json:"type,omitempty"`
}
// Notes a description of the labels used in the test vectors
type Notes struct {
}
// Root
type Root struct {
// the primitive tested in the test file
Algorithm string `json:"algorithm,omitempty"`
// the version of the test vectors.
GeneratorVersion string `json:"generatorVersion,omitempty"`
// additional documentation
Header []string `json:"header,omitempty"`
// a description of the labels used in the test vectors
Notes *Notes `json:"notes,omitempty"`
// the number of test vectors in this test
NumberOfTests int `json:"numberOfTests,omitempty"`
Schema interface{} `json:"schema,omitempty"`
TestGroups []*DsaTestGroup `json:"testGroups,omitempty"`
}
flagsShouldPass := map[string]bool{
// An encoded ASN.1 integer missing a leading zero is invalid, but accepted by some implementations.
"NoLeadingZero": false,
}
var root Root
readTestVector(t, "dsa_test.json", &root)
for _, tg := range root.TestGroups {
pub := decodePublicKey(tg.KeyDer).(*dsa.PublicKey)
h := parseHash(tg.Sha).New()
for _, sig := range tg.Tests {
h.Reset()
h.Write(decodeHex(sig.Msg))
hashed := h.Sum(nil)
hashed = hashed[:pub.Q.BitLen()/8] // Truncate to the byte-length of the subgroup (Q)
got := wdsa.VerifyASN1(pub, hashed, decodeHex(sig.Sig))
if want := shouldPass(sig.Result, sig.Flags, flagsShouldPass); got != want {
t.Errorf("tcid: %d, type: %s, comment: %q, wanted success: %t", sig.TcId, sig.Result, sig.Comment, want)
}
}
}
}
-140
View File
@@ -1,140 +0,0 @@
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package wycheproof
import (
"bytes"
"crypto/ecdh"
"fmt"
"testing"
)
func TestECDHStdLib(t *testing.T) {
type ECDHTestVector struct {
// A brief description of the test case
Comment string `json:"comment,omitempty"`
// A list of flags
Flags []string `json:"flags,omitempty"`
// the private key
Private string `json:"private,omitempty"`
// Encoded public key
Public string `json:"public,omitempty"`
// Test result
Result string `json:"result,omitempty"`
// The shared secret key
Shared string `json:"shared,omitempty"`
// Identifier of the test case
TcID int `json:"tcId,omitempty"`
}
type ECDHTestGroup struct {
Curve string `json:"curve,omitempty"`
Tests []*ECDHTestVector `json:"tests,omitempty"`
}
type Root struct {
TestGroups []*ECDHTestGroup `json:"testGroups,omitempty"`
}
flagsShouldPass := map[string]bool{
// We don't support compressed points.
"CompressedPoint": false,
// We don't support decoding custom curves.
"UnnamedCurve": false,
// WrongOrder and UnusedParam are only found with UnnamedCurve.
"WrongOrder": false,
"UnusedParam": false,
// X25519 specific flags
"Twist": true,
"SmallPublicKey": false,
"LowOrderPublic": false,
"ZeroSharedSecret": false,
"NonCanonicalPublic": true,
}
// curveToCurve is a map of all elliptic curves supported
// by crypto/elliptic, which can subsequently be parsed and tested.
curveToCurve := map[string]ecdh.Curve{
"secp256r1": ecdh.P256(),
"secp384r1": ecdh.P384(),
"secp521r1": ecdh.P521(),
"curve25519": ecdh.X25519(),
}
curveToKeySize := map[string]int{
"secp256r1": 32,
"secp384r1": 48,
"secp521r1": 66,
"curve25519": 32,
}
for _, f := range []string{
"ecdh_secp256r1_ecpoint_test.json",
"ecdh_secp384r1_ecpoint_test.json",
"ecdh_secp521r1_ecpoint_test.json",
"x25519_test.json",
} {
var root Root
readTestVector(t, f, &root)
for _, tg := range root.TestGroups {
if _, ok := curveToCurve[tg.Curve]; !ok {
continue
}
for _, tt := range tg.Tests {
tg, tt := tg, tt
t.Run(fmt.Sprintf("%s/%d", tg.Curve, tt.TcID), func(t *testing.T) {
t.Logf("Type: %v", tt.Result)
t.Logf("Flags: %q", tt.Flags)
t.Log(tt.Comment)
shouldPass := shouldPass(tt.Result, tt.Flags, flagsShouldPass)
curve := curveToCurve[tg.Curve]
p := decodeHex(tt.Public)
pub, err := curve.NewPublicKey(p)
if err != nil {
if shouldPass {
t.Errorf("NewPublicKey: %v", err)
}
return
}
privBytes := decodeHex(tt.Private)
if len(privBytes) != curveToKeySize[tg.Curve] {
t.Skipf("non-standard key size %d", len(privBytes))
}
priv, err := curve.NewPrivateKey(privBytes)
if err != nil {
if shouldPass {
t.Errorf("NewPrivateKey: %v", err)
}
return
}
shared := decodeHex(tt.Shared)
x, err := priv.ECDH(pub)
if err != nil {
if tg.Curve == "curve25519" && !shouldPass {
// ECDH is expected to only return an error when using X25519,
// in all other cases an error is unexpected.
return
}
t.Fatalf("ECDH: %v", err)
}
if bytes.Equal(shared, x) != shouldPass {
if shouldPass {
t.Errorf("ECDH = %x, want %x", shared, x)
} else {
t.Errorf("ECDH = %x, want anything else", shared)
}
}
})
}
}
}
}
-163
View File
@@ -1,163 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package wycheproof
import (
"bytes"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/x509"
"encoding/asn1"
"errors"
"fmt"
"testing"
"golang.org/x/crypto/cryptobyte"
casn1 "golang.org/x/crypto/cryptobyte/asn1"
)
func TestECDH(t *testing.T) {
type ECDHTestVector struct {
// A brief description of the test case
Comment string `json:"comment,omitempty"`
// A list of flags
Flags []string `json:"flags,omitempty"`
// the private key
Private string `json:"private,omitempty"`
// Encoded public key
Public string `json:"public,omitempty"`
// Test result
Result string `json:"result,omitempty"`
// The shared secret key
Shared string `json:"shared,omitempty"`
// Identifier of the test case
TcID int `json:"tcId,omitempty"`
}
type ECDHTestGroup struct {
Curve string `json:"curve,omitempty"`
Tests []*ECDHTestVector `json:"tests,omitempty"`
}
type Root struct {
TestGroups []*ECDHTestGroup `json:"testGroups,omitempty"`
}
flagsShouldPass := map[string]bool{
// ParsePKIXPublicKey doesn't support compressed points, but we test
// them against UnmarshalCompressed anyway.
"CompressedPoint": true,
// We don't support decoding custom curves.
"UnnamedCurve": false,
// WrongOrder and UnusedParam are only found with UnnamedCurve.
"WrongOrder": false,
"UnusedParam": false,
}
// supportedCurves is a map of all elliptic curves supported
// by crypto/elliptic, which can subsequently be parsed and tested.
supportedCurves := map[string]bool{
"secp224r1": true,
"secp256r1": true,
"secp384r1": true,
"secp521r1": true,
}
var root Root
readTestVector(t, "ecdh_test.json", &root)
for _, tg := range root.TestGroups {
if !supportedCurves[tg.Curve] {
continue
}
for _, tt := range tg.Tests {
tg, tt := tg, tt
t.Run(fmt.Sprintf("%s/%d", tg.Curve, tt.TcID), func(t *testing.T) {
t.Logf("Type: %v", tt.Result)
t.Logf("Flags: %q", tt.Flags)
t.Log(tt.Comment)
shouldPass := shouldPass(tt.Result, tt.Flags, flagsShouldPass)
p := decodeHex(tt.Public)
pp, err := x509.ParsePKIXPublicKey(p)
if err != nil {
pp, err = decodeCompressedPKIX(p)
}
if err != nil {
if shouldPass {
t.Errorf("unexpected parsing error: %s", err)
}
return
}
pub := pp.(*ecdsa.PublicKey)
priv := decodeHex(tt.Private)
shared := decodeHex(tt.Shared)
x, _ := pub.Curve.ScalarMult(pub.X, pub.Y, priv)
xBytes := make([]byte, (pub.Curve.Params().BitSize+7)/8)
got := bytes.Equal(shared, x.FillBytes(xBytes))
if want := shouldPass; got != want {
t.Errorf("wanted success %v, got %v", want, got)
}
})
}
}
}
func decodeCompressedPKIX(der []byte) (interface{}, error) {
s := cryptobyte.String(der)
var s1, s2 cryptobyte.String
var algoOID, namedCurveOID asn1.ObjectIdentifier
var pointDER []byte
if !s.ReadASN1(&s1, casn1.SEQUENCE) || !s.Empty() ||
!s1.ReadASN1(&s2, casn1.SEQUENCE) ||
!s2.ReadASN1ObjectIdentifier(&algoOID) ||
!s2.ReadASN1ObjectIdentifier(&namedCurveOID) || !s2.Empty() ||
!s1.ReadASN1BitStringAsBytes(&pointDER) || !s1.Empty() {
return nil, errors.New("failed to parse PKIX structure")
}
if !algoOID.Equal(oidPublicKeyECDSA) {
return nil, errors.New("wrong algorithm OID")
}
namedCurve := namedCurveFromOID(namedCurveOID)
if namedCurve == nil {
return nil, errors.New("unsupported elliptic curve")
}
x, y := elliptic.UnmarshalCompressed(namedCurve, pointDER)
if x == nil {
return nil, errors.New("failed to unmarshal elliptic curve point")
}
pub := &ecdsa.PublicKey{
Curve: namedCurve,
X: x,
Y: y,
}
return pub, nil
}
var (
oidPublicKeyECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}
oidNamedCurveP224 = asn1.ObjectIdentifier{1, 3, 132, 0, 33}
oidNamedCurveP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7}
oidNamedCurveP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34}
oidNamedCurveP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35}
)
func namedCurveFromOID(oid asn1.ObjectIdentifier) elliptic.Curve {
switch {
case oid.Equal(oidNamedCurveP224):
return elliptic.P224()
case oid.Equal(oidNamedCurveP256):
return elliptic.P256()
case oid.Equal(oidNamedCurveP384):
return elliptic.P384()
case oid.Equal(oidNamedCurveP521):
return elliptic.P521()
}
return nil
}
-105
View File
@@ -1,105 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package wycheproof
import (
"crypto/ecdsa"
"math/big"
"testing"
"golang.org/x/crypto/cryptobyte"
"golang.org/x/crypto/cryptobyte/asn1"
)
func TestECDSA(t *testing.T) {
type ASNSignatureTestVector struct {
// A brief description of the test case
Comment string `json:"comment"`
// A list of flags
Flags []string `json:"flags"`
// The message to sign
Msg string `json:"msg"`
// Test result
Result string `json:"result"`
// An ASN.1 encoded signature for msg
Sig string `json:"sig"`
// Identifier of the test case
TcID int `json:"tcId"`
}
type ECPublicKey struct {
// The EC group used by this public key
Curve interface{} `json:"curve"`
}
type ECDSATestGroup struct {
// Unencoded EC public key
Key *ECPublicKey `json:"key"`
// DER encoded public key
KeyDER string `json:"keyDer"`
// the hash function used for ECDSA
SHA string `json:"sha"`
Tests []*ASNSignatureTestVector `json:"tests"`
}
type Root struct {
TestGroups []*ECDSATestGroup `json:"testGroups"`
}
flagsShouldPass := map[string]bool{
// An encoded ASN.1 integer missing a leading zero is invalid, but
// accepted by some implementations.
"MissingZero": false,
// A signature using a weaker hash than the EC params is not a security
// risk, as long as the hash is secure.
// https://www.imperialviolet.org/2014/05/25/strengthmatching.html
"WeakHash": true,
}
// supportedCurves is a map of all elliptic curves supported
// by crypto/elliptic, which can subsequently be parsed and tested.
supportedCurves := map[string]bool{
"secp224r1": true,
"secp256r1": true,
"secp384r1": true,
"secp521r1": true,
}
var root Root
readTestVector(t, "ecdsa_test.json", &root)
for _, tg := range root.TestGroups {
curve := tg.Key.Curve.(string)
if !supportedCurves[curve] {
continue
}
pub := decodePublicKey(tg.KeyDER).(*ecdsa.PublicKey)
h := parseHash(tg.SHA).New()
for _, sig := range tg.Tests {
h.Reset()
h.Write(decodeHex(sig.Msg))
hashed := h.Sum(nil)
sigBytes := decodeHex(sig.Sig)
got := ecdsa.VerifyASN1(pub, hashed, sigBytes)
if want := shouldPass(sig.Result, sig.Flags, flagsShouldPass); got != want {
t.Errorf("tcid: %d, type: %s, comment: %q, VerifyASN1 wanted success: %t", sig.TcID, sig.Result, sig.Comment, want)
}
var r, s big.Int
var inner cryptobyte.String
input := cryptobyte.String(sigBytes)
if !input.ReadASN1(&inner, asn1.SEQUENCE) ||
!input.Empty() ||
!inner.ReadASN1Integer(&r) ||
!inner.ReadASN1Integer(&s) ||
!inner.Empty() {
continue
}
got = ecdsa.Verify(pub, hashed, &r, &s)
if want := shouldPass(sig.Result, sig.Flags, flagsShouldPass); got != want {
t.Errorf("tcid: %d, type: %s, comment: %q, Verify wanted success: %t", sig.TcID, sig.Result, sig.Comment, want)
}
}
}
}
-97
View File
@@ -1,97 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package wycheproof
import (
"crypto/ed25519"
"testing"
)
func TestEddsa(t *testing.T) {
// Jwk the private key in webcrypto format
type Jwk struct {
}
// Key unencoded key pair
type Key struct {
}
// Notes a description of the labels used in the test vectors
type Notes struct {
}
// SignatureTestVector
type SignatureTestVector struct {
// A brief description of the test case
Comment string `json:"comment,omitempty"`
// A list of flags
Flags []string `json:"flags,omitempty"`
// The message to sign
Msg string `json:"msg,omitempty"`
// Test result
Result string `json:"result,omitempty"`
// A signature for msg
Sig string `json:"sig,omitempty"`
// Identifier of the test case
TcId int `json:"tcId,omitempty"`
}
// EddsaTestGroup
type EddsaTestGroup struct {
// the private key in webcrypto format
Jwk *Jwk `json:"jwk,omitempty"`
// unencoded key pair
Key *Key `json:"key,omitempty"`
// Asn encoded public key
KeyDer string `json:"keyDer,omitempty"`
// Pem encoded public key
KeyPem string `json:"keyPem,omitempty"`
Tests []*SignatureTestVector `json:"tests,omitempty"`
Type interface{} `json:"type,omitempty"`
}
// Root
type Root struct {
// the primitive tested in the test file
Algorithm string `json:"algorithm,omitempty"`
// the version of the test vectors.
GeneratorVersion string `json:"generatorVersion,omitempty"`
// additional documentation
Header []string `json:"header,omitempty"`
// a description of the labels used in the test vectors
Notes *Notes `json:"notes,omitempty"`
// the number of test vectors in this test
NumberOfTests int `json:"numberOfTests,omitempty"`
Schema interface{} `json:"schema,omitempty"`
TestGroups []*EddsaTestGroup `json:"testGroups,omitempty"`
}
var root Root
readTestVector(t, "eddsa_test.json", &root)
for _, tg := range root.TestGroups {
pub := decodePublicKey(tg.KeyDer).(ed25519.PublicKey)
for _, sig := range tg.Tests {
got := ed25519.Verify(pub, decodeHex(sig.Msg), decodeHex(sig.Sig))
if want := shouldPass(sig.Result, sig.Flags, nil); got != want {
t.Errorf("tcid: %d, type: %s, comment: %q, wanted success: %t", sig.TcId, sig.Result, sig.Comment, want)
}
}
}
}
-111
View File
@@ -1,111 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package wycheproof
import (
"bytes"
"io"
"testing"
"golang.org/x/crypto/hkdf"
)
func TestHkdf(t *testing.T) {
// HkdfTestVector
type HkdfTestVector struct {
// A brief description of the test case
Comment string `json:"comment,omitempty"`
// A list of flags
Flags []string `json:"flags,omitempty"`
// the key (input key material)
Ikm string `json:"ikm,omitempty"`
// additional information used in the key derivation
Info string `json:"info,omitempty"`
// the generated bytes (output key material)
Okm string `json:"okm,omitempty"`
// Test result
Result string `json:"result,omitempty"`
// the salt for the key derivation
Salt string `json:"salt,omitempty"`
// the size of the output in bytes
Size int `json:"size,omitempty"`
// Identifier of the test case
TcId int `json:"tcId,omitempty"`
}
// Notes a description of the labels used in the test vectors
type Notes struct {
}
// HkdfTestGroup
type HkdfTestGroup struct {
// the size of the ikm in bits
KeySize int `json:"keySize,omitempty"`
Tests []*HkdfTestVector `json:"tests,omitempty"`
Type interface{} `json:"type,omitempty"`
}
// Root
type Root struct {
// the primitive tested in the test file
Algorithm string `json:"algorithm,omitempty"`
// the version of the test vectors.
GeneratorVersion string `json:"generatorVersion,omitempty"`
// additional documentation
Header []string `json:"header,omitempty"`
// a description of the labels used in the test vectors
Notes *Notes `json:"notes,omitempty"`
// the number of test vectors in this test
NumberOfTests int `json:"numberOfTests,omitempty"`
Schema interface{} `json:"schema,omitempty"`
TestGroups []*HkdfTestGroup `json:"testGroups,omitempty"`
}
fileHashAlgorithms := map[string]string{
"hkdf_sha1_test.json": "SHA-1",
"hkdf_sha256_test.json": "SHA-256",
"hkdf_sha384_test.json": "SHA-384",
"hkdf_sha512_test.json": "SHA-512",
}
for f := range fileHashAlgorithms {
var root Root
readTestVector(t, f, &root)
for _, tg := range root.TestGroups {
for _, tv := range tg.Tests {
h := parseHash(fileHashAlgorithms[f]).New
hkdf := hkdf.New(h, decodeHex(tv.Ikm), decodeHex(tv.Salt), decodeHex(tv.Info))
key := make([]byte, tv.Size)
wantPass := shouldPass(tv.Result, tv.Flags, nil)
_, err := io.ReadFull(hkdf, key)
if (err == nil) != wantPass {
t.Errorf("tcid: %d, type: %s, comment: %q, wanted success: %t, got: %v", tv.TcId, tv.Result, tv.Comment, wantPass, err)
}
if err != nil {
continue // don't validate output text if reading failed
}
if got, want := key, decodeHex(tv.Okm); !bytes.Equal(got, want) {
t.Errorf("tcid: %d, type: %s, comment: %q, output bytes don't match", tv.TcId, tv.Result, tv.Comment)
}
}
}
}
}
-105
View File
@@ -1,105 +0,0 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package wycheproof
import (
"crypto/hmac"
"testing"
)
func TestHMAC(t *testing.T) {
// MacTestVector
type MacTestVector struct {
// A brief description of the test case
Comment string `json:"comment,omitempty"`
// A list of flags
Flags []string `json:"flags,omitempty"`
// the key
Key string `json:"key,omitempty"`
// the plaintext
Msg string `json:"msg,omitempty"`
// Test result
Result string `json:"result,omitempty"`
// the authentication tag
Tag string `json:"tag,omitempty"`
// Identifier of the test case
TcId int `json:"tcId,omitempty"`
}
// MacTestGroup
type MacTestGroup struct {
// the keySize in bits
KeySize int `json:"keySize,omitempty"`
// the expected size of the tag in bits
TagSize int `json:"tagSize,omitempty"`
Tests []*MacTestVector `json:"tests,omitempty"`
Type interface{} `json:"type,omitempty"`
}
// Notes a description of the labels used in the test vectors
type Notes struct {
}
// Root
type Root struct {
// the primitive tested in the test file
Algorithm string `json:"algorithm,omitempty"`
// the version of the test vectors.
GeneratorVersion string `json:"generatorVersion,omitempty"`
// additional documentation
Header []string `json:"header,omitempty"`
// a description of the labels used in the test vectors
Notes *Notes `json:"notes,omitempty"`
// the number of test vectors in this test
NumberOfTests int `json:"numberOfTests,omitempty"`
Schema interface{} `json:"schema,omitempty"`
TestGroups []*MacTestGroup `json:"testGroups,omitempty"`
}
fileHashAlgs := map[string]string{
"hmac_sha1_test.json": "SHA-1",
"hmac_sha224_test.json": "SHA-224",
"hmac_sha256_test.json": "SHA-256",
"hmac_sha384_test.json": "SHA-384",
"hmac_sha512_test.json": "SHA-512",
}
for f := range fileHashAlgs {
var root Root
readTestVector(t, f, &root)
for _, tg := range root.TestGroups {
h := parseHash(fileHashAlgs[f])
// Skip test vectors where the tag length does not equal the
// hash length, since crypto/hmac does not support generating
// these truncated tags.
if tg.TagSize/8 != h.Size() {
continue
}
for _, tv := range tg.Tests {
hm := hmac.New(h.New, decodeHex(tv.Key))
hm.Write(decodeHex(tv.Msg))
tag := hm.Sum(nil)
got := hmac.Equal(decodeHex(tv.Tag), tag)
if want := shouldPass(tv.Result, tv.Flags, nil); want != got {
t.Errorf("%s, tcid: %d, type: %s, comment: %q, unexpected result", f, tv.TcId, tv.Result, tv.Comment)
}
}
}
}
}
-33
View File
@@ -1,33 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package dsa provides an internal version of dsa.Verify
// that is used for the Wycheproof tests.
package dsa
import (
"crypto/dsa"
"math/big"
"golang.org/x/crypto/cryptobyte"
"golang.org/x/crypto/cryptobyte/asn1"
)
// VerifyASN1 verifies the ASN1 encoded signature, sig, of hash using the
// public key, pub. Its return value records whether the signature is valid.
func VerifyASN1(pub *dsa.PublicKey, hash, sig []byte) bool {
var (
r, s = &big.Int{}, &big.Int{}
inner cryptobyte.String
)
input := cryptobyte.String(sig)
if !input.ReadASN1(&inner, asn1.SEQUENCE) ||
!input.Empty() ||
!inner.ReadASN1Integer(r) ||
!inner.ReadASN1Integer(s) ||
!inner.Empty() {
return false
}
return dsa.Verify(pub, hash, r, s)
}
-9
View File
@@ -1,9 +0,0 @@
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !boringcrypto
package wycheproof
const boringcryptoEnabled = false
@@ -1,149 +0,0 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package wycheproof
import (
"bytes"
"crypto/rsa"
"crypto/x509"
"fmt"
"testing"
)
func TestRSAOAEPDecrypt(t *testing.T) {
// Notes a description of the labels used in the test vectors
type Notes struct {
}
// RsaesOaepTestVector
type RsaesOaepTestVector struct {
// A brief description of the test case
Comment string `json:"comment,omitempty"`
// An encryption of msg
Ct string `json:"ct,omitempty"`
// A list of flags
Flags []string `json:"flags,omitempty"`
// The label used for the encryption
Label string `json:"label,omitempty"`
// The encrypted message
Msg string `json:"msg,omitempty"`
// Test result
Result string `json:"result,omitempty"`
// Identifier of the test case
TcId int `json:"tcId,omitempty"`
}
// RsaesOaepTestGroup
type RsaesOaepTestGroup struct {
// The private exponent
D string `json:"d,omitempty"`
// The public exponent
E string `json:"e,omitempty"`
// the message generating function (e.g. MGF1)
Mgf string `json:"mgf,omitempty"`
// The hash function used for the message generating function.
MgfSha string `json:"mgfSha,omitempty"`
// The modulus of the key
N string `json:"n,omitempty"`
// Pem encoded private key
PrivateKeyPem string `json:"privateKeyPem,omitempty"`
// Pkcs 8 encoded private key.
PrivateKeyPkcs8 string `json:"privateKeyPkcs8,omitempty"`
// The hash function for hashing the label.
Sha string `json:"sha,omitempty"`
Tests []*RsaesOaepTestVector `json:"tests,omitempty"`
Type interface{} `json:"type,omitempty"`
}
// Root
type Root struct {
// the primitive tested in the test file
Algorithm string `json:"algorithm,omitempty"`
// the version of the test vectors.
GeneratorVersion string `json:"generatorVersion,omitempty"`
// additional documentation
Header []string `json:"header,omitempty"`
// a description of the labels used in the test vectors
Notes *Notes `json:"notes,omitempty"`
// the number of test vectors in this test
NumberOfTests int `json:"numberOfTests,omitempty"`
Schema interface{} `json:"schema,omitempty"`
TestGroups []*RsaesOaepTestGroup `json:"testGroups,omitempty"`
}
// rsa.DecryptOAEP doesn't support using a different hash for the
// MGF and the label, so skip all of the test vectors that use
// these unbalanced constructions. rsa_oaep_misc_test.json contains
// both balanced and unbalanced constructions so in that case
// we just filter out any test groups where MgfSha != Sha
files := []string{
"rsa_oaep_2048_sha1_mgf1sha1_test.json",
"rsa_oaep_2048_sha224_mgf1sha224_test.json",
"rsa_oaep_2048_sha256_mgf1sha256_test.json",
"rsa_oaep_2048_sha384_mgf1sha384_test.json",
"rsa_oaep_2048_sha512_mgf1sha512_test.json",
"rsa_oaep_3072_sha256_mgf1sha256_test.json",
"rsa_oaep_3072_sha512_mgf1sha512_test.json",
"rsa_oaep_4096_sha256_mgf1sha256_test.json",
"rsa_oaep_4096_sha512_mgf1sha512_test.json",
"rsa_oaep_misc_test.json",
}
flagsShouldPass := map[string]bool{
// rsa.DecryptOAEP happily supports small key sizes
"SmallModulus": true,
}
for _, f := range files {
var root Root
readTestVector(t, f, &root)
for _, tg := range root.TestGroups {
if tg.MgfSha != tg.Sha {
continue
}
priv, err := x509.ParsePKCS8PrivateKey(decodeHex(tg.PrivateKeyPkcs8))
if err != nil {
t.Fatalf("%s failed to parse PKCS #8 private key: %s", f, err)
}
hash := parseHash(tg.Sha)
for _, tv := range tg.Tests {
t.Run(fmt.Sprintf("%s #%d", f, tv.TcId), func(t *testing.T) {
wantPass := shouldPass(tv.Result, tv.Flags, flagsShouldPass)
plaintext, err := rsa.DecryptOAEP(hash.New(), nil, priv.(*rsa.PrivateKey), decodeHex(tv.Ct), decodeHex(tv.Label))
if wantPass {
if err != nil {
t.Fatalf("comment: %s, expected success: %s", tv.Comment, err)
}
if !bytes.Equal(plaintext, decodeHex(tv.Msg)) {
t.Errorf("comment: %s, unexpected plaintext: got %x, want %s", tv.Comment, plaintext, tv.Msg)
}
} else if err == nil {
t.Errorf("comment: %s, expected failure", tv.Comment)
}
})
}
}
}
}
-169
View File
@@ -1,169 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package wycheproof
import (
"crypto/rsa"
"testing"
)
func TestRsaPss(t *testing.T) {
// KeyJwk Public key in JWK format
type KeyJwk struct {
}
// Notes a description of the labels used in the test vectors
type Notes struct {
}
// SignatureTestVector
type SignatureTestVector struct {
// A brief description of the test case
Comment string `json:"comment,omitempty"`
// A list of flags
Flags []string `json:"flags,omitempty"`
// The message to sign
Msg string `json:"msg,omitempty"`
// Test result
Result string `json:"result,omitempty"`
// A signature for msg
Sig string `json:"sig,omitempty"`
// Identifier of the test case
TcId int `json:"tcId,omitempty"`
}
// RsassaPkcs1TestGroup
type RsassaPkcs1TestGroup struct {
// The private exponent
D string `json:"d,omitempty"`
// The public exponent
E string `json:"e,omitempty"`
// ASN encoding of the sequence [n, e]
KeyAsn string `json:"keyAsn,omitempty"`
// ASN encoding of the public key
KeyDer string `json:"keyDer,omitempty"`
// Public key in JWK format
KeyJwk *KeyJwk `json:"keyJwk,omitempty"`
// Pem encoded public key
KeyPem string `json:"keyPem,omitempty"`
// the size of the modulus in bits
KeySize int `json:"keySize,omitempty"`
// The modulus of the key
N string `json:"n,omitempty"`
// The salt length
SLen int `json:"sLen,omitempty"`
// the hash function used for the message
Sha string `json:"sha,omitempty"`
Tests []*SignatureTestVector `json:"tests,omitempty"`
Type interface{} `json:"type,omitempty"`
}
// Root
type Root struct {
// the primitive tested in the test file
Algorithm string `json:"algorithm,omitempty"`
// the version of the test vectors.
GeneratorVersion string `json:"generatorVersion,omitempty"`
// additional documentation
Header []string `json:"header,omitempty"`
// a description of the labels used in the test vectors
Notes *Notes `json:"notes,omitempty"`
// the number of test vectors in this test
NumberOfTests int `json:"numberOfTests,omitempty"`
Schema interface{} `json:"schema,omitempty"`
TestGroups []*RsassaPkcs1TestGroup `json:"testGroups,omitempty"`
}
flagsShouldPass := map[string]bool{
// A signature using a weaker hash than the EC params is not a security risk, as long as the hash is secure.
// https://www.imperialviolet.org/2014/05/25/strengthmatching.html
"WeakHash": true,
}
// filesOverrideToPassZeroSLen is a map of all test files
// and which TcIds that should be overridden to pass if the
// rsa.PSSOptions.SaltLength is zero.
// These tests expect a failure with a PSSOptions.SaltLength: 0
// and a signature that uses a different salt length. However,
// a salt length of 0 is defined as rsa.PSSSaltLengthAuto which
// works deterministically to auto-detect the length when
// verifying, so these tests actually pass as they should.
filesOverrideToPassZeroSLen := map[string][]int{
"rsa_pss_2048_sha1_mgf1_20_test.json": []int{46, 47},
"rsa_pss_2048_sha256_mgf1_0_test.json": []int{67, 68},
"rsa_pss_2048_sha256_mgf1_32_test.json": []int{67, 68},
"rsa_pss_3072_sha256_mgf1_32_test.json": []int{67, 68},
"rsa_pss_4096_sha256_mgf1_32_test.json": []int{67, 68},
"rsa_pss_4096_sha512_mgf1_32_test.json": []int{136, 137},
// "rsa_pss_misc_test.json": nil, // TODO: This ones seems to be broken right now, but can enable later on.
}
if !boringcryptoEnabled {
// boringcrypto doesn't support the truncated SHA-512 hashes, so only
// test them if boringcrypto isn't enabled.
filesOverrideToPassZeroSLen["rsa_pss_2048_sha512_256_mgf1_28_test.json"] = []int{13, 14, 15}
filesOverrideToPassZeroSLen["rsa_pss_2048_sha512_256_mgf1_32_test.json"] = []int{13, 14}
}
for f := range filesOverrideToPassZeroSLen {
var root Root
readTestVector(t, f, &root)
for _, tg := range root.TestGroups {
pub := decodePublicKey(tg.KeyDer).(*rsa.PublicKey)
ch := parseHash(tg.Sha)
h := ch.New()
opts := &rsa.PSSOptions{
Hash: ch,
SaltLength: rsa.PSSSaltLengthAuto,
}
// Run all the tests twice: the first time with the salt length
// as PSSSaltLengthAuto, and the second time with the salt length
// explicitly set to tg.SLen.
for i := 0; i < 2; i++ {
for _, sig := range tg.Tests {
h.Reset()
h.Write(decodeHex(sig.Msg))
hashed := h.Sum(nil)
err := rsa.VerifyPSS(pub, ch, hashed, decodeHex(sig.Sig), opts)
want := shouldPass(sig.Result, sig.Flags, flagsShouldPass)
if opts.SaltLength == 0 {
for _, id := range filesOverrideToPassZeroSLen[f] {
if sig.TcId == id {
want = true
break
}
}
}
if (err == nil) != want {
t.Errorf("file: %v, tcid: %d, type: %s, opts.SaltLength: %v, comment: %q, wanted success: %t", f, sig.TcId, sig.Result, opts.SaltLength, sig.Comment, want)
}
}
// Update opts.SaltLength for the second run of the tests.
opts.SaltLength = tg.SLen
}
}
}
}
-123
View File
@@ -1,123 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package wycheproof
import (
"crypto/rsa"
"testing"
)
func TestRsa(t *testing.T) {
// KeyJwk Public key in JWK format
type KeyJwk struct {
}
// Notes a description of the labels used in the test vectors
type Notes struct {
}
// SignatureTestVector
type SignatureTestVector struct {
// A brief description of the test case
Comment string `json:"comment,omitempty"`
// A list of flags
Flags []string `json:"flags,omitempty"`
// The message to sign
Msg string `json:"msg,omitempty"`
// Test result
Result string `json:"result,omitempty"`
// A signature for msg
Sig string `json:"sig,omitempty"`
// Identifier of the test case
TcId int `json:"tcId,omitempty"`
}
// RsassaPkcs1TestGroup
type RsassaPkcs1TestGroup struct {
// The private exponent
D string `json:"d,omitempty"`
// The public exponent
E string `json:"e,omitempty"`
// ASN encoding of the sequence [n, e]
KeyAsn string `json:"keyAsn,omitempty"`
// ASN encoding of the public key
KeyDer string `json:"keyDer,omitempty"`
// Public key in JWK format
KeyJwk *KeyJwk `json:"keyJwk,omitempty"`
// Pem encoded public key
KeyPem string `json:"keyPem,omitempty"`
// the size of the modulus in bits
KeySize int `json:"keySize,omitempty"`
// The modulus of the key
N string `json:"n,omitempty"`
// the hash function used for the message
Sha string `json:"sha,omitempty"`
Tests []*SignatureTestVector `json:"tests,omitempty"`
Type interface{} `json:"type,omitempty"`
}
// Root
type Root struct {
// the primitive tested in the test file
Algorithm string `json:"algorithm,omitempty"`
// the version of the test vectors.
GeneratorVersion string `json:"generatorVersion,omitempty"`
// additional documentation
Header []string `json:"header,omitempty"`
// a description of the labels used in the test vectors
Notes *Notes `json:"notes,omitempty"`
// the number of test vectors in this test
NumberOfTests int `json:"numberOfTests,omitempty"`
Schema interface{} `json:"schema,omitempty"`
TestGroups []*RsassaPkcs1TestGroup `json:"testGroups,omitempty"`
}
flagsShouldPass := map[string]bool{
// Omitting the parameter field in an ASN encoded integer is a legacy behavior.
"MissingNull": false,
// Keys with a modulus less than 2048 bits are supported by crypto/rsa.
"SmallModulus": true,
// Small public keys are supported by crypto/rsa.
"SmallPublicKey": true,
}
var root Root
readTestVector(t, "rsa_signature_test.json", &root)
for _, tg := range root.TestGroups {
pub := decodePublicKey(tg.KeyDer).(*rsa.PublicKey)
ch := parseHash(tg.Sha)
h := ch.New()
for _, sig := range tg.Tests {
h.Reset()
h.Write(decodeHex(sig.Msg))
hashed := h.Sum(nil)
err := rsa.VerifyPKCS1v15(pub, ch, hashed, decodeHex(sig.Sig))
want := shouldPass(sig.Result, sig.Flags, flagsShouldPass)
if (err == nil) != want {
t.Errorf("tcid: %d, type: %s, comment: %q, wanted success: %t", sig.TcId, sig.Result, sig.Comment, want)
}
}
}
}
-141
View File
@@ -1,141 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package wycheproof runs a set of the Wycheproof tests
// provided by https://github.com/google/wycheproof.
package wycheproof
import (
"crypto"
"crypto/x509"
"encoding/hex"
"encoding/json"
"flag"
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"testing"
_ "crypto/sha1"
_ "crypto/sha256"
_ "crypto/sha512"
)
const wycheproofModVer = "v0.0.0-20191219022705-2196000605e4"
var wycheproofTestVectorsDir string
func TestMain(m *testing.M) {
flag.Parse()
if flag.Lookup("test.short").Value.(flag.Getter).Get().(bool) {
log.Println("skipping test that downloads testdata via 'go mod download' in short mode")
os.Exit(0)
}
if _, err := exec.LookPath("go"); err != nil {
log.Printf("skipping test because 'go' command is unavailable: %v", err)
os.Exit(0)
}
if os.Getenv("GO_BUILDER_FLAKY_NET") != "" {
log.Printf("skipping test because GO_BUILDER_FLAKY_NET is set")
os.Exit(0)
}
// Download the JSON test files from github.com/google/wycheproof
// using `go mod download -json` so the cached source of the testdata
// can be used in the following tests.
path := "github.com/google/wycheproof@" + wycheproofModVer
cmd := exec.Command("go", "mod", "download", "-json", path)
output, err := cmd.Output()
if err != nil {
log.Fatalf("failed to run `go mod download -json %s`, output: %s", path, output)
}
var dm struct {
Dir string // absolute path to cached source root directory
}
if err := json.Unmarshal(output, &dm); err != nil {
log.Fatal(err)
}
// Now that the module has been downloaded, use the absolute path of the
// cached source as the root directory for all tests going forward.
wycheproofTestVectorsDir = filepath.Join(dm.Dir, "testvectors")
os.Exit(m.Run())
}
func readTestVector(t *testing.T, f string, dest interface{}) {
b, err := os.ReadFile(filepath.Join(wycheproofTestVectorsDir, f))
if err != nil {
t.Fatalf("failed to read json file: %v", err)
}
if err := json.Unmarshal(b, &dest); err != nil {
t.Fatalf("failed to unmarshal json file: %v", err)
}
}
func decodeHex(s string) []byte {
b, err := hex.DecodeString(s)
if err != nil {
panic(err)
}
return b
}
func decodePublicKey(der string) interface{} {
d := decodeHex(der)
pub, err := x509.ParsePKIXPublicKey(d)
if err != nil {
panic(fmt.Sprintf("failed to parse DER encoded public key: %v", err))
}
return pub
}
func parseHash(h string) crypto.Hash {
switch h {
case "SHA-1":
return crypto.SHA1
case "SHA-256":
return crypto.SHA256
case "SHA-224":
return crypto.SHA224
case "SHA-384":
return crypto.SHA384
case "SHA-512":
return crypto.SHA512
case "SHA-512/224":
return crypto.SHA512_224
case "SHA-512/256":
return crypto.SHA512_256
default:
panic(fmt.Sprintf("could not identify SHA hash algorithm: %q", h))
}
}
// shouldPass returns whether or not the test should pass.
// flagsShouldPass is a map associated with whether or not
// a flag for an "acceptable" result should pass.
// Every possible flag value that's associated with an
// "acceptable" result should be explicitly specified,
// otherwise the test will panic.
func shouldPass(result string, flags []string, flagsShouldPass map[string]bool) bool {
switch result {
case "valid":
return true
case "invalid":
return false
case "acceptable":
for _, flag := range flags {
pass, ok := flagsShouldPass[flag]
if !ok {
panic(fmt.Sprintf("unspecified flag: %q", flag))
}
if !pass {
return false
}
}
return true // There are no flags, or all are meant to pass.
default:
panic(fmt.Sprintf("unexpected result: %v", result))
}
}
+6 -5
View File
@@ -5,11 +5,12 @@
// Package armor implements OpenPGP ASCII Armor, see RFC 4880. OpenPGP Armor is
// very similar to PEM except that it has an additional CRC checksum.
//
// Deprecated: this package is unmaintained except for security fixes. New
// applications should consider a more focused, modern alternative to OpenPGP
// for their specific task. If you are required to interoperate with OpenPGP
// systems and need a maintained package, consider a community fork.
// See https://golang.org/issue/44226.
// Deprecated: this package is unsafe by design, and has numerous known security
// issues. It is not maintained, and should not be used. New applications should
// consider a more focused, modern alternative to OpenPGP for their specific
// task. If you are required to interoperate with OpenPGP systems and need a
// maintained package, consider github.com/ProtonMail/go-crypto/openpgp, which
// is a maintained fork that aims to be a drop-in replacement for this package.
package armor
import (
+6 -5
View File
@@ -8,11 +8,12 @@
// Clearsigned messages are cryptographically signed, but the contents of the
// message are kept in plaintext so that it can be read without special tools.
//
// Deprecated: this package is unmaintained except for security fixes. New
// applications should consider a more focused, modern alternative to OpenPGP
// for their specific task. If you are required to interoperate with OpenPGP
// systems and need a maintained package, consider a community fork.
// See https://golang.org/issue/44226.
// Deprecated: this package is unsafe by design, and has numerous known security
// issues. It is not maintained, and should not be used. New applications should
// consider a more focused, modern alternative to OpenPGP for their specific
// task. If you are required to interoperate with OpenPGP systems and need a
// maintained package, consider github.com/ProtonMail/go-crypto/openpgp, which
// is a maintained fork that aims to be a drop-in replacement for this package.
package clearsign
import (
+6 -5
View File
@@ -4,11 +4,12 @@
// Package errors contains common error types for the OpenPGP packages.
//
// Deprecated: this package is unmaintained except for security fixes. New
// applications should consider a more focused, modern alternative to OpenPGP
// for their specific task. If you are required to interoperate with OpenPGP
// systems and need a maintained package, consider a community fork.
// See https://golang.org/issue/44226.
// Deprecated: this package is unsafe by design, and has numerous known security
// issues. It is not maintained, and should not be used. New applications should
// consider a more focused, modern alternative to OpenPGP for their specific
// task. If you are required to interoperate with OpenPGP systems and need a
// maintained package, consider github.com/ProtonMail/go-crypto/openpgp, which
// is a maintained fork that aims to be a drop-in replacement for this package.
package errors
import (
+6 -5
View File
@@ -5,11 +5,12 @@
// Package packet implements parsing and serialization of OpenPGP packets, as
// specified in RFC 4880.
//
// Deprecated: this package is unmaintained except for security fixes. New
// applications should consider a more focused, modern alternative to OpenPGP
// for their specific task. If you are required to interoperate with OpenPGP
// systems and need a maintained package, consider a community fork.
// See https://golang.org/issue/44226.
// Deprecated: this package is unsafe by design, and has numerous known security
// issues. It is not maintained, and should not be used. New applications should
// consider a more focused, modern alternative to OpenPGP for their specific
// task. If you are required to interoperate with OpenPGP systems and need a
// maintained package, consider github.com/ProtonMail/go-crypto/openpgp, which
// is a maintained fork that aims to be a drop-in replacement for this package.
package packet
import (
+6 -5
View File
@@ -4,11 +4,12 @@
// Package openpgp implements high level operations on OpenPGP messages.
//
// Deprecated: this package is unmaintained except for security fixes. New
// applications should consider a more focused, modern alternative to OpenPGP
// for their specific task. If you are required to interoperate with OpenPGP
// systems and need a maintained package, consider a community fork.
// See https://golang.org/issue/44226.
// Deprecated: this package is unsafe by design, and has numerous known security
// issues. It is not maintained, and should not be used. New applications should
// consider a more focused, modern alternative to OpenPGP for their specific
// task. If you are required to interoperate with OpenPGP systems and need a
// maintained package, consider github.com/ProtonMail/go-crypto/openpgp, which
// is a maintained fork that aims to be a drop-in replacement for this package.
package openpgp
import (
+6 -5
View File
@@ -5,11 +5,12 @@
// Package s2k implements the various OpenPGP string-to-key transforms as
// specified in RFC 4800 section 3.7.1.
//
// Deprecated: this package is unmaintained except for security fixes. New
// applications should consider a more focused, modern alternative to OpenPGP
// for their specific task. If you are required to interoperate with OpenPGP
// systems and need a maintained package, consider a community fork.
// See https://golang.org/issue/44226.
// Deprecated: this package is unsafe by design, and has numerous known security
// issues. It is not maintained, and should not be used. New applications should
// consider a more focused, modern alternative to OpenPGP for their specific
// task. If you are required to interoperate with OpenPGP systems and need a
// maintained package, consider github.com/ProtonMail/go-crypto/openpgp, which
// is a maintained fork that aims to be a drop-in replacement for this package.
package s2k
import (
+2
View File
@@ -41,6 +41,7 @@ func ForwardToAgent(client *ssh.Client, keyring Agent) error {
continue
}
go ssh.DiscardRequests(reqs)
go io.Copy(io.Discard, channel.Stderr())
go func() {
ServeAgent(keyring, channel)
channel.Close()
@@ -72,6 +73,7 @@ func ForwardToRemote(client *ssh.Client, addr string) error {
continue
}
go ssh.DiscardRequests(reqs)
go io.Copy(io.Discard, channel.Stderr())
go forwardUnixSocket(channel, addr)
}
}()
+47 -6
View File
@@ -304,19 +304,60 @@ func parseEd25519Key(req []byte) (*AddedKey, error) {
return addedKey, nil
}
func checkDSAParams(param *dsa.Parameters) error {
// SSH specifies FIPS 186-2, which only provided a single size
// (1024 bits) DSA key. FIPS 186-3 allows for larger key
// sizes, which would confuse SSH.
if l := param.P.BitLen(); l != 1024 {
return fmt.Errorf("ssh: unsupported DSA key size %d", l)
}
// FIPS 186-2 specifies that Q must be exactly 160 bits. We must enforce
// this to prevent DoS attacks where an attacker sends a huge Q which makes
// verification slow.
if l := param.Q.BitLen(); l != 160 {
return fmt.Errorf("ssh: unsupported DSA sub-prime size %d", l)
}
// The generator G is an element of the group, so it must be strictly less
// than the modulus P.
if param.G.Cmp(param.P) >= 0 {
return errors.New("ssh: DSA generator larger than modulus")
}
// G must be positive.
if param.G.Sign() <= 0 {
return errors.New("ssh: DSA generator must be positive")
}
return nil
}
func parseDSAKey(req []byte) (*AddedKey, error) {
var k dsaKeyMsg
if err := ssh.Unmarshal(req, &k); err != nil {
return nil, err
}
params := dsa.Parameters{
P: k.P,
Q: k.Q,
G: k.G,
}
if err := checkDSAParams(&params); err != nil {
return nil, err
}
// The public value Y must be a non-zero element of the group, i.e. strictly
// between 0 and P, to prevent a maliciously oversized Y from slowing
// signature operations.
if k.Y.Sign() <= 0 || k.Y.Cmp(k.P) >= 0 {
return nil, errors.New("agent: DSA public value Y out of range")
}
priv := &dsa.PrivateKey{
PublicKey: dsa.PublicKey{
Parameters: dsa.Parameters{
P: k.P,
Q: k.Q,
G: k.G,
},
Y: k.Y,
Parameters: params,
Y: k.Y,
},
X: k.X,
}
+161
View File
@@ -9,10 +9,12 @@ import (
"crypto/rand"
"fmt"
"io"
"math/big"
pseudorand "math/rand"
"reflect"
"strings"
"testing"
"time"
"golang.org/x/crypto/ssh"
)
@@ -88,6 +90,96 @@ func TestSetupForwardAgent(t *testing.T) {
conn.Close()
}
func TestForwardAgentDiscardsStderr(t *testing.T) {
a, b, err := netPipe()
if err != nil {
t.Fatalf("netPipe: %v", err)
}
defer a.Close()
defer b.Close()
serverConf := ssh.ServerConfig{
NoClientAuth: true,
}
serverConf.AddHostKey(testSigners["rsa"])
incoming := make(chan *ssh.ServerConn, 1)
go func() {
conn, _, _, err := ssh.NewServerConn(a, &serverConf)
incoming <- conn
if err != nil {
t.Errorf("NewServerConn error: %v", err)
return
}
}()
conf := ssh.ClientConfig{
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}
conn, chans, reqs, err := ssh.NewClientConn(b, "", &conf)
if err != nil {
t.Fatalf("NewClientConn: %v", err)
}
client := ssh.NewClient(conn, chans, reqs)
defer client.Close()
if err := ForwardToAgent(client, NewKeyring()); err != nil {
t.Fatalf("ForwardToAgent: %v", err)
}
server := <-incoming
if server == nil {
t.Fatal("Unable to get server")
}
defer server.Close()
ch, chanReqs, err := server.OpenChannel(channelType, nil)
if err != nil {
t.Fatalf("OpenChannel(%q): %v", channelType, err)
}
go ssh.DiscardRequests(chanReqs)
defer ch.Close()
// Write more than the default channel receive window (2 MiB) on the
// stderr stream. If the forwarder did not drain it the remote window
// would be exhausted and this write would block forever, because no
// window-adjust messages are emitted for an extended stream that is
// never read.
const payload = 4 * 1024 * 1024
done := make(chan error, 1)
go func() {
buf := make([]byte, 32*1024)
remaining := payload
for remaining > 0 {
n := len(buf)
if remaining < n {
n = remaining
}
w, err := ch.Stderr().Write(buf[:n])
if err != nil {
done <- err
return
}
remaining -= w
}
done <- nil
}()
select {
case err := <-done:
if err != nil {
t.Fatalf("write to stderr: %v", err)
}
case <-time.After(10 * time.Second):
t.Fatal("write to stderr blocked: ForwardToAgent is not draining channel.Stderr()")
}
// The agent must still be reachable on the main stream after the
// stderr traffic.
if _, err := NewClient(ch).List(); err != nil {
t.Fatalf("List after stderr flood: %v", err)
}
}
func TestV1ProtocolMessages(t *testing.T) {
c1, c2, err := netPipe()
if err != nil {
@@ -154,6 +246,75 @@ func addKeyToAgent(key crypto.PrivateKey) error {
return verifyKey(sshAgent)
}
func TestParseDSAKeyHugeQ(t *testing.T) {
P := new(big.Int).Lsh(big.NewInt(1), 1023)
Q := new(big.Int).Lsh(big.NewInt(1), 20000) // very large
// G and Y: dummy values, just needs to be < P to pass that specific check.
G := big.NewInt(2)
Y := big.NewInt(5)
req := ssh.Marshal(dsaKeyMsg{
Type: ssh.InsecureKeyAlgoDSA,
P: P,
Q: Q,
G: G,
Y: Y,
X: big.NewInt(1),
})
_, err := parseDSAKey(req)
if err == nil {
t.Fatal("parseDSAKey accepted a DSA key with large Q")
}
expectedError := "unsupported DSA sub-prime size"
if !strings.Contains(err.Error(), expectedError) {
t.Errorf("unexpected error message: got %q, want substring %q", err.Error(), expectedError)
}
}
func TestParseDSAKeyYOutOfRange(t *testing.T) {
// Valid 1024/160 parameters (values don't need to be a real DSA group,
// they only need to pass the checkDSAParams bit-length checks and the
// G < P / G > 0 checks).
P := new(big.Int).Lsh(big.NewInt(1), 1023)
P.SetBit(P, 0, 1) // make P odd so it can pass as a prime candidate shape
Q := new(big.Int).Lsh(big.NewInt(1), 159)
Q.SetBit(Q, 0, 1)
G := big.NewInt(2)
for _, tc := range []struct {
name string
Y *big.Int
}{
{"Y_zero", big.NewInt(0)},
{"Y_negative", big.NewInt(-1)},
{"Y_equals_P", new(big.Int).Set(P)},
{"Y_greater_than_P", new(big.Int).Add(P, big.NewInt(1))},
{"Y_much_greater_than_P", new(big.Int).Lsh(big.NewInt(1), 20000)},
} {
t.Run(tc.name, func(t *testing.T) {
req := ssh.Marshal(dsaKeyMsg{
Type: ssh.InsecureKeyAlgoDSA,
P: P,
Q: Q,
G: G,
Y: tc.Y,
X: big.NewInt(1),
})
_, err := parseDSAKey(req)
if err == nil {
t.Fatalf("parseDSAKey accepted a DSA key with Y=%s (P=%s)", tc.Y, P)
}
expectedError := "DSA public value Y out of range"
if !strings.Contains(err.Error(), expectedError) {
t.Errorf("unexpected error message: got %q, want substring %q", err.Error(), expectedError)
}
})
}
}
func TestKeyTypes(t *testing.T) {
for k, v := range testPrivateKeys {
if err := addKeyToAgent(v); err != nil {
+26 -10
View File
@@ -182,14 +182,19 @@ func ParseKnownHosts(in []byte) (marker string, hosts []string, pubKey PublicKey
}
hosts := string(keyFields[0])
// keyFields[1] contains the key type (e.g. “ssh-rsa”).
// However, that information is duplicated inside the
// base64-encoded key and so is ignored here.
// keyFields[1] contains the key type (e.g. "ssh-rsa"). This information
// is duplicated within the base64-encoded key blob. As OpenSSH's
// sshkey_read does, we verify that the declared key type matches the
// type embedded in the key blob.
wantType := string(keyFields[1])
key := bytes.Join(keyFields[2:], []byte(" "))
if pubKey, comment, err = parseAuthorizedKey(key); err != nil {
return "", nil, nil, "", nil, err
}
if pubKey.Type() != wantType {
return "", nil, nil, "", nil, fmt.Errorf("ssh: known hosts key type mismatch: human-readable type %q, encoded type %q", wantType, pubKey.Type())
}
return marker, strings.Split(hosts, ","), pubKey, comment, rest, nil
}
@@ -228,10 +233,17 @@ func ParseAuthorizedKey(in []byte) (out PublicKey, comment string, options []str
}
if out, comment, err = parseAuthorizedKey(in[i:]); err == nil {
return out, comment, options, rest, nil
} else {
lastErr = err
// The first field contains the declared key type. As OpenSSH's
// sshkey_read does, we verify that it matches the type embedded in
// the key blob. Without this check, a single-token option (e.g.
// "restrict") appearing in the key type position could be silently
// discarded along with its intended effect.
if string(in[:i]) == out.Type() {
return out, comment, options, rest, nil
}
err = fmt.Errorf("ssh: authorized keys key type mismatch: human-readable type %q, encoded type %q", in[:i], out.Type())
}
lastErr = err
// No key type recognised. Maybe there's an options field at
// the beginning.
@@ -271,11 +283,15 @@ func ParseAuthorizedKey(in []byte) (out PublicKey, comment string, options []str
}
if out, comment, err = parseAuthorizedKey(in[i:]); err == nil {
options = candidateOptions
return out, comment, options, rest, nil
} else {
lastErr = err
// As above, the declared key type (here following the options
// field) must match the type embedded in the key blob.
if string(in[:i]) == out.Type() {
options = candidateOptions
return out, comment, options, rest, nil
}
err = fmt.Errorf("ssh: authorized keys key type mismatch: human-readable type %q, encoded type %q", in[:i], out.Type())
}
lastErr = err
in = rest
continue
+66
View File
@@ -848,6 +848,65 @@ func TestInvalidEntry(t *testing.T) {
}
}
func TestAuthorizedKeyOptionWithoutKeyType(t *testing.T) {
_, pubSerialized := getTestKey()
for _, opt := range []string{"restrict", "no-pty", "no-port-forwarding", "no-agent-forwarding"} {
// The key type ("ssh-rsa") is intentionally omitted.
line := opt + " " + pubSerialized
testAuthorizedKeys(t, []byte(line), []testAuthResult{
{nil, nil, "", "", false},
})
}
}
func TestAuthorizedKeyTypeMismatch(t *testing.T) {
_, pubSerialized := getTestKey() // an ssh-rsa key
lines := []string{
"ssh-ed25519 " + pubSerialized + " user@host",
"restrict ssh-ed25519 " + pubSerialized + " user@host",
"rsa-sha2-512 " + pubSerialized + " user@host",
}
for _, line := range lines {
testAuthorizedKeys(t, []byte(line), []testAuthResult{
{nil, nil, "", "", false},
})
}
}
func TestAuthorizedKeyCertificate(t *testing.T) {
certLine := testdata.SSHCertificates["rsa-user-testcertificate"]
key, _, options, _, err := ParseAuthorizedKey(certLine)
if err != nil {
t.Fatalf("ParseAuthorizedKey on certificate: %v", err)
}
if _, ok := key.(*Certificate); !ok {
t.Fatalf("got %T, want *Certificate", key)
}
if len(options) != 0 {
t.Errorf("got options %v, want none", options)
}
key, _, options, _, err = ParseAuthorizedKey(append([]byte("cert-authority "), certLine...))
if err != nil {
t.Fatalf("ParseAuthorizedKey on cert-authority certificate: %v", err)
}
if _, ok := key.(*Certificate); !ok {
t.Fatalf("got %T, want *Certificate", key)
}
if !reflect.DeepEqual(options, []string{"cert-authority"}) {
t.Errorf("got options %v, want [cert-authority]", options)
}
}
func TestAuthorizedKeyOptionWithKeyType(t *testing.T) {
pub, pubSerialized := getTestKey()
line := "restrict ssh-rsa " + pubSerialized + " user@host"
testAuthorizedKeys(t, []byte(line), []testAuthResult{
{pub, []string{"restrict"}, "user@host", "", true},
})
}
var knownHostsParseTests = []struct {
input string
err string
@@ -927,6 +986,13 @@ var knownHostsParseTests = []struct {
"@marker \tlocalhost,[host2:123]\tssh-rsa aabbccdd",
"short read",
"", "", nil, "",
},
{
// Declared key type does not match the type embedded in the blob.
"localhost ssh-ed25519 {RSAPUB}",
"key type mismatch",
"", "", nil, "",
},
}
+10 -1
View File
@@ -44,7 +44,16 @@ type disconnectMsg struct {
}
func (d *disconnectMsg) Error() string {
return fmt.Sprintf("ssh: disconnect, reason %d: %s", d.Reason, d.Message)
return fmt.Sprintf("ssh: disconnect, reason %d: %q", d.Reason, sanitizeString(d.Message))
}
func sanitizeString(s string) string {
return strings.Map(func(r rune) rune {
if r == '\t' || (r >= ' ' && r < 0x7f) {
return r
}
return -1
}, s)
}
// See RFC 4253, section 7.1.
+28 -2
View File
@@ -9,6 +9,7 @@ import (
"math/big"
"math/rand"
"reflect"
"strings"
"testing"
"testing/quick"
)
@@ -262,6 +263,31 @@ func TestDecode(t *testing.T) {
}
}
func TestDisconnectMsgSanitizesMessage(t *testing.T) {
for _, tc := range []struct {
in string
want string
}{
{"clean message", `"clean message"`},
{"line1\nline2\nline3", `"line1line2line3"`},
{"has\x00null\x00bytes", `"hasnullbytes"`},
{"\x1b[31mred\x1b[0m", `"[31mred[0m"`},
{"newline\r\nCRLF", `"newlineCRLF"`},
{"tab\there", `"tab\there"`},
} {
t.Run(tc.in, func(t *testing.T) {
d := &disconnectMsg{Reason: 11, Message: tc.in}
got := d.Error()
if !strings.Contains(got, tc.want) {
t.Errorf("got %q, want %q", got, tc.want)
}
if bad := "\n\r\x00\x1b"; strings.ContainsAny(got, bad) {
t.Errorf("got %q, want none of %q", got, bad)
}
})
}
}
func randomBytes(out []byte, rand *rand.Rand) {
for i := 0; i < len(out); i++ {
out[i] = byte(rand.Int31())
@@ -318,7 +344,7 @@ var (
)
func BenchmarkMarshalKexInitMsg(b *testing.B) {
for i := 0; i < b.N; i++ {
for b.Loop() {
Marshal(_kexInitMsg)
}
}
@@ -331,7 +357,7 @@ func BenchmarkUnmarshalKexInitMsg(b *testing.B) {
}
func BenchmarkMarshalKexDHInitMsg(b *testing.B) {
for i := 0; i < b.N; i++ {
for b.Loop() {
Marshal(_kexDHInitMsg)
}
}
Binary file not shown.
+79 -92
View File
@@ -237,492 +237,479 @@ var unparsedCertificates = []unparsedCertificate{
certStartOff: 40789,
certLength: 1428,
},
{
cn: "CN=Entrust Root Certification Authority,OU=www.entrust.net/CPS is incorporated by reference+OU=(c) 2006 Entrust\\, Inc.,O=Entrust\\, Inc.,C=US",
sha256Hash: "73c176434f1bc6d5adf45b0e76e727287c8de57616c1e6e6141a2b2cbc7d8e4c",
certStartOff: 42217,
certLength: 1173,
distrustAfter: "2024-11-30T23:59:59Z",
},
{
cn: "CN=GDCA TrustAUTH R5 ROOT,O=GUANG DONG CERTIFICATE AUTHORITY CO.\\,LTD.,C=CN",
sha256Hash: "bfff8fd04433487d6a8aa60c1a29767a9fc2bbb05e420f713a13b992891d3893",
certStartOff: 43390,
certStartOff: 42217,
certLength: 1420,
},
{
cn: "CN=GTS Root R1,O=Google Trust Services LLC,C=US",
sha256Hash: "d947432abde7b7fa90fc2e6b59101b1280e0e1c7e4e40fa3c6887fff57a7f4cf",
certStartOff: 44810,
certStartOff: 43637,
certLength: 1371,
},
{
cn: "CN=GTS Root R3,O=Google Trust Services LLC,C=US",
sha256Hash: "34d8a73ee208d9bcdb0d956520934b4e40e69482596e8b6f73c8426b010a6f48",
certStartOff: 46181,
certStartOff: 45008,
certLength: 525,
},
{
cn: "CN=GTS Root R4,O=Google Trust Services LLC,C=US",
sha256Hash: "349dfa4058c5e263123b398ae795573c4e1313c83fe68f93556cd5e8031b3c7d",
certStartOff: 46706,
certStartOff: 45533,
certLength: 525,
},
{
cn: "CN=GlobalSign Root E46,O=GlobalSign nv-sa,C=BE",
sha256Hash: "cbb9c44d84b8043e1050ea31a69f514955d7bfd2e2c6b49301019ad61d9f5058",
certStartOff: 47231,
certStartOff: 46058,
certLength: 527,
},
{
cn: "CN=GlobalSign Root R46,O=GlobalSign nv-sa,C=BE",
sha256Hash: "4fa3126d8d3a11d1c4855a4f807cbad6cf919d3a5a88b03bea2c6372d93c40c9",
certStartOff: 47758,
certStartOff: 46585,
certLength: 1374,
},
{
cn: "CN=GlobalSign,OU=GlobalSign ECC Root CA - R4,O=GlobalSign",
sha256Hash: "b085d70b964f191a73e4af0d54ae7a0e07aafdaf9b71dd0862138ab7325a24a2",
certStartOff: 49132,
certStartOff: 47959,
certLength: 480,
},
{
cn: "CN=GlobalSign,OU=GlobalSign ECC Root CA - R5,O=GlobalSign",
sha256Hash: "179fbc148a3dd00fd24ea13458cc43bfa7f59c8182d783a513f6ebec100c8924",
certStartOff: 49612,
certStartOff: 48439,
certLength: 546,
},
{
cn: "CN=GlobalSign,OU=GlobalSign Root CA - R3,O=GlobalSign",
sha256Hash: "cbb522d7b7f127ad6a0113865bdf1cd4102e7d0759af635a7cf4720dc963c53b",
certStartOff: 50158,
certStartOff: 48985,
certLength: 867,
},
{
cn: "CN=GlobalSign,OU=GlobalSign Root CA - R6,O=GlobalSign",
sha256Hash: "2cabeafe37d06ca22aba7391c0033d25982952c453647349763a3ab5ad6ccf69",
certStartOff: 51025,
certStartOff: 49852,
certLength: 1415,
},
{
cn: "CN=Go Daddy Root Certificate Authority - G2,O=GoDaddy.com\\, Inc.,L=Scottsdale,ST=Arizona,C=US",
sha256Hash: "45140b3247eb9cc8c5b4f0d7b53091f73292089e6e5a63e2749dd3aca9198eda",
certStartOff: 52440,
certStartOff: 51267,
certLength: 969,
},
{
cn: "CN=HARICA TLS ECC Root CA 2021,O=Hellenic Academic and Research Institutions CA,C=GR",
sha256Hash: "3f99cc474acfce4dfed58794665e478d1547739f2e780f1bb4ca9b133097d401",
certStartOff: 53409,
certStartOff: 52236,
certLength: 600,
},
{
cn: "CN=HARICA TLS RSA Root CA 2021,O=Hellenic Academic and Research Institutions CA,C=GR",
sha256Hash: "d95d0e8eda79525bf9beb11b14d2100d3294985f0c62d9fabd9cd999eccb7b1d",
certStartOff: 54009,
certStartOff: 52836,
certLength: 1448,
},
{
cn: "CN=Hellenic Academic and Research Institutions ECC RootCA 2015,O=Hellenic Academic and Research Institutions Cert. Authority,L=Athens,C=GR",
sha256Hash: "44b545aa8a25e65a73ca15dc27fc36d24c1cb9953a066539b11582dc487b4833",
certStartOff: 55457,
certStartOff: 54284,
certLength: 711,
},
{
cn: "CN=Hellenic Academic and Research Institutions RootCA 2015,O=Hellenic Academic and Research Institutions Cert. Authority,L=Athens,C=GR",
sha256Hash: "a040929a02ce53b4acf4f2ffc6981ce4496f755e6d45fe0b2a692bcd52523f36",
certStartOff: 56168,
certStartOff: 54995,
certLength: 1551,
},
{
cn: "CN=HiPKI Root CA - G1,O=Chunghwa Telecom Co.\\, Ltd.,C=TW",
sha256Hash: "f015ce3cc239bfef064be9f1d2c417e1a0264a0a94be1f0c8d121864eb6949cc",
certStartOff: 57719,
certStartOff: 56546,
certLength: 1390,
},
{
cn: "CN=Hongkong Post Root CA 3,O=Hongkong Post,L=Hong Kong,ST=Hong Kong,C=HK",
sha256Hash: "5a2fc03f0c83b090bbfa40604b0988446c7636183df9846e17101a447fb8efd6",
certStartOff: 59109,
certStartOff: 57936,
certLength: 1491,
},
{
cn: "CN=ISRG Root X1,O=Internet Security Research Group,C=US",
sha256Hash: "96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6",
certStartOff: 60600,
certStartOff: 59427,
certLength: 1391,
},
{
cn: "CN=ISRG Root X2,O=Internet Security Research Group,C=US",
sha256Hash: "69729b8e15a86efc177a57afb7171dfc64add28c2fca8cf1507e34453ccb1470",
certStartOff: 61991,
certStartOff: 60818,
certLength: 543,
},
{
cn: "CN=IdenTrust Commercial Root CA 1,O=IdenTrust,C=US",
sha256Hash: "5d56499be4d2e08bcfcad08a3e38723d50503bde706948e42f55603019e528ae",
certStartOff: 62534,
certStartOff: 61361,
certLength: 1380,
},
{
cn: "CN=IdenTrust Public Sector Root CA 1,O=IdenTrust,C=US",
sha256Hash: "30d0895a9a448a262091635522d1f52010b5867acae12c78ef958fd4f4389f2f",
certStartOff: 63914,
certStartOff: 62741,
certLength: 1386,
},
{
cn: "CN=Izenpe.com,O=IZENPE S.A.,C=ES",
sha256Hash: "2530cc8e98321502bad96f9b1fba1b099e2d299e0f4548bb914f363bc0d4531f",
certStartOff: 65300,
certStartOff: 64127,
certLength: 1525,
},
{
cn: "CN=Microsec e-Szigno Root CA 2009,O=Microsec Ltd.,L=Budapest,C=HU,1.2.840.113549.1.9.1=#0c10696e666f40652d737a69676e6f2e6875",
sha256Hash: "3c5f81fea5fab82c64bfa2eaecafcde8e077fc8620a7cae537163df36edbf378",
certStartOff: 66825,
certStartOff: 65652,
certLength: 1038,
},
{
cn: "CN=Microsoft ECC Root Certificate Authority 2017,O=Microsoft Corporation,C=US",
sha256Hash: "358df39d764af9e1b766e9c972df352ee15cfac227af6ad1d70e8e4a6edcba02",
certStartOff: 67863,
certStartOff: 66690,
certLength: 605,
},
{
cn: "CN=Microsoft RSA Root Certificate Authority 2017,O=Microsoft Corporation,C=US",
sha256Hash: "c741f70f4b2a8d88bf2e71c14122ef53ef10eba0cfa5e64cfa20f418853073e0",
certStartOff: 68468,
certStartOff: 67295,
certLength: 1452,
},
{
cn: "CN=NAVER Global Root Certification Authority,O=NAVER BUSINESS PLATFORM Corp.,C=KR",
sha256Hash: "88f438dcf8ffd1fa8f429115ffe5f82ae1e06e0c70c375faad717b34a49e7265",
certStartOff: 69920,
certStartOff: 68747,
certLength: 1446,
},
{
cn: "CN=NetLock Arany (Class Gold) Főtanúsítvány,OU=Tanúsítványkiadók (Certification Services),O=NetLock Kft.,L=Budapest,C=HU",
sha256Hash: "6c61dac3a2def031506be036d2a6fe401994fbd13df9c8d466599274c446ec98",
certStartOff: 71366,
certStartOff: 70193,
certLength: 1049,
},
{
cn: "CN=OISTE Server Root ECC G1,O=OISTE Foundation,C=CH",
sha256Hash: "eec997c0c30f216f7e3b8b307d2bae42412d753fc8219dafd1520b2572850f49",
certStartOff: 72415,
certStartOff: 71242,
certLength: 569,
},
{
cn: "CN=OISTE Server Root RSA G1,O=OISTE Foundation,C=CH",
sha256Hash: "9ae36232a5189ffddb353dfd26520c015395d22777dac59db57b98c089a651e6",
certStartOff: 72984,
certStartOff: 71811,
certLength: 1415,
},
{
cn: "CN=OISTE WISeKey Global Root GB CA,OU=OISTE Foundation Endorsed,O=WISeKey,C=CH",
sha256Hash: "6b9c08e86eb0f767cfad65cd98b62149e5494a67f5845e7bd1ed019f27b86bd6",
certStartOff: 74399,
certStartOff: 73226,
certLength: 953,
},
{
cn: "CN=OISTE WISeKey Global Root GC CA,OU=OISTE Foundation Endorsed,O=WISeKey,C=CH",
sha256Hash: "8560f91c3624daba9570b5fea0dbe36ff11a8323be9486854fb3f34a5571198d",
certStartOff: 75352,
certStartOff: 74179,
certLength: 621,
},
{
cn: "CN=QuoVadis Root CA 1 G3,O=QuoVadis Limited,C=BM",
sha256Hash: "8a866fd1b276b57e578e921c65828a2bed58e9f2f288054134b7f1f4bfc9cc74",
certStartOff: 75973,
certStartOff: 74800,
certLength: 1380,
},
{
cn: "CN=QuoVadis Root CA 2 G3,O=QuoVadis Limited,C=BM",
sha256Hash: "8fe4fb0af93a4d0d67db0bebb23e37c71bf325dcbcdd240ea04daf58b47e1840",
certStartOff: 77353,
certStartOff: 76180,
certLength: 1380,
},
{
cn: "CN=QuoVadis Root CA 3 G3,O=QuoVadis Limited,C=BM",
sha256Hash: "88ef81de202eb018452e43f864725cea5fbd1fc2d9d205730709c5d8b8690f46",
certStartOff: 78733,
certStartOff: 77560,
certLength: 1380,
},
{
cn: "CN=SSL.com EV Root Certification Authority ECC,O=SSL Corporation,L=Houston,ST=Texas,C=US",
sha256Hash: "22a2c1f7bded704cc1e701b5f408c310880fe956b5de2a4a44f99c873a25a7c8",
certStartOff: 80113,
certStartOff: 78940,
certLength: 664,
},
{
cn: "CN=SSL.com EV Root Certification Authority RSA R2,O=SSL Corporation,L=Houston,ST=Texas,C=US",
sha256Hash: "2e7bf16cc22485a7bbe2aa8696750761b0ae39be3b2fe9d0cc6d4ef73491425c",
certStartOff: 80777,
certStartOff: 79604,
certLength: 1519,
},
{
cn: "CN=SSL.com Root Certification Authority ECC,O=SSL Corporation,L=Houston,ST=Texas,C=US",
sha256Hash: "3417bb06cc6007da1b961c920b8ab4ce3fad820e4aa30b9acbc4a74ebdcebc65",
certStartOff: 82296,
certStartOff: 81123,
certLength: 657,
},
{
cn: "CN=SSL.com Root Certification Authority RSA,O=SSL Corporation,L=Houston,ST=Texas,C=US",
sha256Hash: "85666a562ee0be5ce925c1d8890a6f76a87ec16d4d7d5f29ea7419cf20123b69",
certStartOff: 82953,
certStartOff: 81780,
certLength: 1505,
},
{
cn: "CN=SSL.com TLS ECC Root CA 2022,O=SSL Corporation,C=US",
sha256Hash: "c32ffd9f46f936d16c3673990959434b9ad60aafbb9e7cf33654f144cc1ba143",
certStartOff: 84458,
certStartOff: 83285,
certLength: 574,
},
{
cn: "CN=SSL.com TLS RSA Root CA 2022,O=SSL Corporation,C=US",
sha256Hash: "8faf7d2e2cb4709bb8e0b33666bf75a5dd45b5de480f8ea8d4bfe6bebc17f2ed",
certStartOff: 85032,
certStartOff: 83859,
certLength: 1421,
},
{
cn: "CN=SZAFIR ROOT CA2,O=Krajowa Izba Rozliczeniowa S.A.,C=PL",
sha256Hash: "a1339d33281a0b56e557d3d32b1ce7f9367eb094bd5fa72a7e5004c8ded7cafe",
certStartOff: 86453,
certStartOff: 85280,
certLength: 886,
},
{
cn: "CN=Sectigo Public Server Authentication Root E46,O=Sectigo Limited,C=GB",
sha256Hash: "c90f26f0fb1b4018b22227519b5ca2b53e2ca5b3be5cf18efe1bef47380c5383",
certStartOff: 87339,
certStartOff: 86166,
certLength: 574,
},
{
cn: "CN=Sectigo Public Server Authentication Root R46,O=Sectigo Limited,C=GB",
sha256Hash: "7bb647a62aeeac88bf257aa522d01ffea395e0ab45c73f93f65654ec38f25a06",
certStartOff: 87913,
certStartOff: 86740,
certLength: 1422,
},
{
cn: "CN=SecureSign Root CA12,O=Cybertrust Japan Co.\\, Ltd.,C=JP",
sha256Hash: "3f034bb5704d44b2d08545a02057de93ebf3905fce721acbc730c06ddaee904e",
certStartOff: 89335,
certLength: 886,
},
{
cn: "CN=SecureSign Root CA14,O=Cybertrust Japan Co.\\, Ltd.,C=JP",
sha256Hash: "4b009c1034494f9ab56bba3ba1d62731fc4d20d8955adcec10a925607261e338",
certStartOff: 90221,
certStartOff: 88162,
certLength: 1398,
},
{
cn: "CN=SecureSign Root CA15,O=Cybertrust Japan Co.\\, Ltd.,C=JP",
sha256Hash: "e778f0f095fe843729cd1a0082179e5314a9c291442805e1fb1d8fb6b8886c3a",
certStartOff: 91619,
certStartOff: 89560,
certLength: 551,
},
{
cn: "CN=Security Communication ECC RootCA1,O=SECOM Trust Systems CO.\\,LTD.,C=JP",
sha256Hash: "e74fbda55bd564c473a36b441aa799c8a68e077440e8288b9fa1e50e4bbaca11",
certStartOff: 92170,
certStartOff: 90111,
certLength: 572,
},
{
cn: "CN=Starfield Root Certificate Authority - G2,O=Starfield Technologies\\, Inc.,L=Scottsdale,ST=Arizona,C=US",
sha256Hash: "2ce1cb0bf9d2f9e102993fbe215152c3b2dd0cabde1c68e5319b839154dbb7f5",
certStartOff: 92742,
certStartOff: 90683,
certLength: 993,
},
{
cn: "CN=Starfield Services Root Certificate Authority - G2,O=Starfield Technologies\\, Inc.,L=Scottsdale,ST=Arizona,C=US",
sha256Hash: "568d6905a2c88708a4b3025190edcfedb1974a606a13c6e5290fcb2ae63edab5",
certStartOff: 93735,
certStartOff: 91676,
certLength: 1011,
},
{
cn: "CN=SwissSign RSA TLS Root CA 2022 - 1,O=SwissSign AG,C=CH",
sha256Hash: "193144f431e0fddb740717d4de926a571133884b4360d30e272913cbe660ce41",
certStartOff: 94746,
certStartOff: 92687,
certLength: 1431,
},
{
cn: "CN=T-TeleSec GlobalRoot Class 2,OU=T-Systems Trust Center,O=T-Systems Enterprise Services GmbH,C=DE",
sha256Hash: "91e2f5788d5810eba7ba58737de1548a8ecacd014598bc0b143e041b17052552",
certStartOff: 96177,
certStartOff: 94118,
certLength: 967,
},
{
cn: "CN=T-TeleSec GlobalRoot Class 3,OU=T-Systems Trust Center,O=T-Systems Enterprise Services GmbH,C=DE",
sha256Hash: "fd73dad31c644ff1b43bef0ccdda96710b9cd9875eca7e31707af3e96d522bbd",
certStartOff: 97144,
certStartOff: 95085,
certLength: 967,
},
{
cn: "CN=TWCA CYBER Root CA,OU=Root CA,O=TAIWAN-CA,C=TW",
sha256Hash: "3f63bb2814be174ec8b6439cf08d6d56f0b7c405883a5648a334424d6b3ec558",
certStartOff: 98111,
certStartOff: 96052,
certLength: 1425,
},
{
cn: "CN=TWCA Global Root CA,OU=Root CA,O=TAIWAN-CA,C=TW",
sha256Hash: "59769007f7685d0fcd50872f9f95d5755a5b2b457d81f3692b610a98672f0e1b",
certStartOff: 99536,
certStartOff: 97477,
certLength: 1349,
},
{
cn: "CN=TWCA Root Certification Authority,OU=Root CA,O=TAIWAN-CA,C=TW",
sha256Hash: "bfd88fe1101c41ae3e801bf8be56350ee9bad1a6b9bd515edc5c6d5b8711ac44",
certStartOff: 100885,
certStartOff: 98826,
certLength: 895,
},
{
cn: "CN=Telekom Security TLS ECC Root 2020,O=Deutsche Telekom Security GmbH,C=DE",
sha256Hash: "578af4ded0853f4e5998db4aeaf9cbea8d945f60b620a38d1a3c13b2bc7ba8e1",
certStartOff: 101780,
certStartOff: 99721,
certLength: 582,
},
{
cn: "CN=Telekom Security TLS RSA Root 2023,O=Deutsche Telekom Security GmbH,C=DE",
sha256Hash: "efc65cadbb59adb6efe84da22311b35624b71b3b1ea0da8b6655174ec8978646",
certStartOff: 102362,
certStartOff: 100303,
certLength: 1463,
},
{
cn: "CN=Telia Root CA v2,O=Telia Finland Oyj,C=FI",
sha256Hash: "242b69742fcb1e5b2abf98898b94572187544e5b4d9911786573621f6a74b82c",
certStartOff: 103825,
certStartOff: 101766,
certLength: 1400,
},
{
cn: "CN=TrustAsia Global Root CA G3,O=TrustAsia Technologies\\, Inc.,C=CN",
sha256Hash: "e0d3226aeb1163c2e48ff9be3b50b4c6431be7bb1eacc5c36b5d5ec509039a08",
certStartOff: 105225,
certStartOff: 103166,
certLength: 1449,
},
{
cn: "CN=TrustAsia Global Root CA G4,O=TrustAsia Technologies\\, Inc.,C=CN",
sha256Hash: "be4b56cb5056c0136a526df444508daa36a0b54f42e4ac38f72af470e479654c",
certStartOff: 106674,
certStartOff: 104615,
certLength: 601,
},
{
cn: "CN=TrustAsia TLS ECC Root CA,O=TrustAsia Technologies\\, Inc.,C=CN",
sha256Hash: "c0076b9ef0531fb1a656d67c4ebe97cd5dbaa41ef44598acc2489878c92d8711",
certStartOff: 107275,
certStartOff: 105216,
certLength: 565,
},
{
cn: "CN=TrustAsia TLS RSA Root CA,O=TrustAsia Technologies\\, Inc.,C=CN",
sha256Hash: "06c08d7dafd876971eb1124fe67f847ec0c7a158d3ea53cbe940e2ea9791f4c3",
certStartOff: 107840,
certStartOff: 105781,
certLength: 1412,
},
{
cn: "CN=TunTrust Root CA,O=Agence Nationale de Certification Electronique,C=TN",
sha256Hash: "2e44102ab58cb85419451c8e19d9acf3662cafbc614b6a53960a30f7d0e2eb41",
certStartOff: 109252,
certStartOff: 107193,
certLength: 1463,
},
{
cn: "CN=UCA Extended Validation Root,O=UniTrust,C=CN",
sha256Hash: "d43af9b35473755c9684fc06d7d8cb70ee5c28e773fb294eb41ee71722924d24",
certStartOff: 110715,
certStartOff: 108656,
certLength: 1374,
},
{
cn: "CN=UCA Global G2 Root,O=UniTrust,C=CN",
sha256Hash: "9bea11c976fe014764c1be56a6f914b5a560317abd9988393382e5161aa0493c",
certStartOff: 112089,
certStartOff: 110030,
certLength: 1354,
},
{
cn: "CN=USERTrust ECC Certification Authority,O=The USERTRUST Network,L=Jersey City,ST=New Jersey,C=US",
sha256Hash: "4ff460d54b9c86dabfbcfc5712e0400d2bed3fbc4d4fbdaa86e06adcd2a9ad7a",
certStartOff: 113443,
certStartOff: 111384,
certLength: 659,
},
{
cn: "CN=USERTrust RSA Certification Authority,O=The USERTRUST Network,L=Jersey City,ST=New Jersey,C=US",
sha256Hash: "e793c9b02fd8aa13e21c31228accb08119643b749c898964b1746d46c3d4cbd2",
certStartOff: 114102,
certStartOff: 112043,
certLength: 1506,
},
{
cn: "CN=e-Szigno Root CA 2017,O=Microsec Ltd.,L=Budapest,C=HU,2.5.4.97=#130e56415448552d3233353834343937",
sha256Hash: "beb00b30839b9bc32c32e4447905950641f26421b15ed089198b518ae2ea1b99",
certStartOff: 115608,
certStartOff: 113549,
certLength: 580,
},
{
cn: "CN=e-Szigno TLS Root CA 2023,O=Microsec Ltd.,L=Budapest,C=HU,2.5.4.97=#130e56415448552d3233353834343937",
sha256Hash: "b49141502d00663d740f2e7ec340c52800962666121a36d09cf7dd2b90384fb4",
certStartOff: 116188,
certStartOff: 114129,
certLength: 723,
},
{
cn: "CN=emSign ECC Root CA - C3,OU=emSign PKI,O=eMudhra Inc,C=US",
sha256Hash: "bc4d809b15189d78db3e1d8cf4f9726a795da1643ca5f1358e1ddb0edc0d7eb3",
certStartOff: 116911,
certStartOff: 114852,
certLength: 559,
},
{
cn: "CN=emSign ECC Root CA - G3,OU=emSign PKI,O=eMudhra Technologies Limited,C=IN",
sha256Hash: "86a1ecba089c4a8d3bbe2734c612ba341d813e043cf9e8a862cd5c57a36bbe6b",
certStartOff: 117470,
certStartOff: 115411,
certLength: 594,
},
{
cn: "CN=emSign Root CA - C1,OU=emSign PKI,O=eMudhra Inc,C=US",
sha256Hash: "125609aa301da0a249b97a8239cb6a34216f44dcac9f3954b14292f2e8c8608f",
certStartOff: 118064,
certStartOff: 116005,
certLength: 887,
},
{
cn: "CN=emSign Root CA - G1,OU=emSign PKI,O=eMudhra Technologies Limited,C=IN",
sha256Hash: "40f6af0346a99aa1cd1d555a4e9cce62c7f9634603ee406615833dc8c8d00367",
certStartOff: 118951,
certStartOff: 116892,
certLength: 920,
},
{
cn: "CN=vTrus ECC Root CA,O=iTrusChina Co.\\,Ltd.,C=CN",
sha256Hash: "30fbba2c32238e2a98547af97931e550428b9b3f1c8eeb6633dcfa86c5b27dd3",
certStartOff: 119871,
certStartOff: 117812,
certLength: 531,
},
{
cn: "CN=vTrus Root CA,O=iTrusChina Co.\\,Ltd.,C=CN",
sha256Hash: "8a71de6559336f426c26e53880d00d88a18da4c6a91f0dcb6194e206c5c96387",
certStartOff: 120402,
certStartOff: 118343,
certLength: 1370,
},
{
cn: "OU=AC RAIZ FNMT-RCM,O=FNMT-RCM,C=ES",
sha256Hash: "ebc5570c29018c4d67b1aa127baf12f703b4611ebc17b7dab5573894179b93fa",
certStartOff: 121772,
certStartOff: 119713,
certLength: 1415,
},
{
cn: "OU=Security Communication RootCA2,O=SECOM Trust Systems CO.\\,LTD.,C=JP",
sha256Hash: "513b2cecb810d4cde5dd85391adfc6c2dd60d87bb736d2b521484aa47a0ebef6",
certStartOff: 123187,
certStartOff: 121128,
certLength: 891,
},
{
cn: "OU=certSIGN ROOT CA G2,O=CERTSIGN SA,C=RO",
sha256Hash: "657cfe2fa73faa38462571f332a2363a46fce7020951710702cdfbb6eeda3305",
certStartOff: 124078,
certStartOff: 122019,
certLength: 1355,
},
{
cn: "OU=ePKI Root Certification Authority,O=Chunghwa Telecom Co.\\, Ltd.,C=TW",
sha256Hash: "c0a6f4dc63a24bfdcf54ef2a6a082a0a72de35803e2ff5ff527ae5d87206dfd5",
certStartOff: 125433,
certStartOff: 123374,
certLength: 1460,
distrustAfter: "2025-04-15T23:59:59Z",
},
{
cn: "SERIALNUMBER=G63287510,CN=ANF Secure Server Root CA,OU=ANF CA Raiz,O=ANF Autoridad de Certificacion,C=ES",
sha256Hash: "fb8fec759169b9106b1e511644c618c51304373f6c0643088d8beffd1b997599",
certStartOff: 126893,
certStartOff: 124834,
certLength: 1523,
},
}