summaryrefslogtreecommitdiff
path: root/src/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'src/crypto')
-rw-r--r--src/crypto/dsa/dsa.go6
-rw-r--r--src/crypto/hmac/hmac.go15
-rw-r--r--src/crypto/hmac/hmac_test.go24
-rw-r--r--src/crypto/rand/eagain.go4
-rw-r--r--src/crypto/rand/rand.go6
-rw-r--r--src/crypto/rand/rand_unix.go4
-rw-r--r--src/crypto/rand/rand_windows.go40
-rw-r--r--src/crypto/tls/common.go16
-rw-r--r--src/crypto/tls/conn.go12
-rw-r--r--src/crypto/tls/handshake_test.go4
-rw-r--r--src/crypto/tls/tls_test.go7
-rw-r--r--src/crypto/x509/internal/macos/corefoundation.go2
-rw-r--r--src/crypto/x509/internal/macos/corefoundation.s2
-rw-r--r--src/crypto/x509/internal/macos/security.go2
-rw-r--r--src/crypto/x509/internal/macos/security.s2
-rw-r--r--src/crypto/x509/pem_decrypt.go35
-rw-r--r--src/crypto/x509/root.go2
-rw-r--r--src/crypto/x509/root_cgo_darwin.go (renamed from src/crypto/x509/root_cgo_darwin_amd64.go)0
-rw-r--r--src/crypto/x509/root_darwin.go (renamed from src/crypto/x509/root_darwin_amd64.go)0
-rw-r--r--src/crypto/x509/root_ios.go (renamed from src/crypto/x509/root_darwin_iosx.go)4
-rw-r--r--src/crypto/x509/root_ios_gen.go (renamed from src/crypto/x509/root_darwin_ios_gen.go)13
-rw-r--r--src/crypto/x509/root_unix.go7
-rw-r--r--src/crypto/x509/x509.go53
-rw-r--r--src/crypto/x509/x509_test.go139
24 files changed, 241 insertions, 158 deletions
diff --git a/src/crypto/dsa/dsa.go b/src/crypto/dsa/dsa.go
index 43826bcb55..a83359996d 100644
--- a/src/crypto/dsa/dsa.go
+++ b/src/crypto/dsa/dsa.go
@@ -5,6 +5,12 @@
// Package dsa implements the Digital Signature Algorithm, as defined in FIPS 186-3.
//
// The DSA operations in this package are not implemented using constant-time algorithms.
+//
+// Deprecated: DSA is a legacy algorithm, and modern alternatives such as
+// Ed25519 (implemented by package crypto/ed25519) should be used instead. Keys
+// with 1024-bit moduli (L1024N160 parameters) are cryptographically weak, while
+// bigger keys are not widely supported. Note that FIPS 186-5 no longer approves
+// DSA for signature generation.
package dsa
import (
diff --git a/src/crypto/hmac/hmac.go b/src/crypto/hmac/hmac.go
index a6ba71c275..cdda33c2cb 100644
--- a/src/crypto/hmac/hmac.go
+++ b/src/crypto/hmac/hmac.go
@@ -120,6 +120,8 @@ func (h *hmac) Reset() {
}
// New returns a new HMAC hash using the given hash.Hash type and key.
+// New functions like sha256.New from crypto/sha256 can be used as h.
+// h must return a new Hash every time it is called.
// Note that unlike other hash implementations in the standard library,
// the returned Hash does not implement encoding.BinaryMarshaler
// or encoding.BinaryUnmarshaler.
@@ -127,6 +129,19 @@ func New(h func() hash.Hash, key []byte) hash.Hash {
hm := new(hmac)
hm.outer = h()
hm.inner = h()
+ unique := true
+ func() {
+ defer func() {
+ // The comparison might panic if the underlying types are not comparable.
+ _ = recover()
+ }()
+ if hm.outer == hm.inner {
+ unique = false
+ }
+ }()
+ if !unique {
+ panic("crypto/hmac: hash generation function does not produce unique values")
+ }
blocksize := hm.inner.BlockSize()
hm.ipad = make([]byte, blocksize)
hm.opad = make([]byte, blocksize)
diff --git a/src/crypto/hmac/hmac_test.go b/src/crypto/hmac/hmac_test.go
index 453bfb3b7f..25e67d7fe5 100644
--- a/src/crypto/hmac/hmac_test.go
+++ b/src/crypto/hmac/hmac_test.go
@@ -556,6 +556,17 @@ func TestHMAC(t *testing.T) {
}
}
+func TestNonUniqueHash(t *testing.T) {
+ sha := sha256.New()
+ defer func() {
+ err := recover()
+ if err == nil {
+ t.Error("expected panic when calling New with a non-unique hash generation function")
+ }
+ }()
+ New(func() hash.Hash { return sha }, []byte("bytes"))
+}
+
// justHash implements just the hash.Hash methods and nothing else
type justHash struct {
hash.Hash
@@ -587,8 +598,8 @@ func BenchmarkHMACSHA256_1K(b *testing.B) {
b.SetBytes(int64(len(buf)))
for i := 0; i < b.N; i++ {
h.Write(buf)
- h.Reset()
mac := h.Sum(nil)
+ h.Reset()
buf[0] = mac[0]
}
}
@@ -600,7 +611,18 @@ func BenchmarkHMACSHA256_32(b *testing.B) {
b.SetBytes(int64(len(buf)))
for i := 0; i < b.N; i++ {
h.Write(buf)
+ mac := h.Sum(nil)
h.Reset()
+ buf[0] = mac[0]
+ }
+}
+
+func BenchmarkNewWriteSum(b *testing.B) {
+ buf := make([]byte, 32)
+ b.SetBytes(int64(len(buf)))
+ for i := 0; i < b.N; i++ {
+ h := New(sha256.New, make([]byte, 32))
+ h.Write(buf)
mac := h.Sum(nil)
buf[0] = mac[0]
}
diff --git a/src/crypto/rand/eagain.go b/src/crypto/rand/eagain.go
index f251ba28fc..c9499715dc 100644
--- a/src/crypto/rand/eagain.go
+++ b/src/crypto/rand/eagain.go
@@ -7,7 +7,7 @@
package rand
import (
- "os"
+ "io/fs"
"syscall"
)
@@ -18,7 +18,7 @@ func init() {
// unixIsEAGAIN reports whether err is a syscall.EAGAIN wrapped in a PathError.
// See golang.org/issue/9205
func unixIsEAGAIN(err error) bool {
- if pe, ok := err.(*os.PathError); ok {
+ if pe, ok := err.(*fs.PathError); ok {
if errno, ok := pe.Err.(syscall.Errno); ok && errno == syscall.EAGAIN {
return true
}
diff --git a/src/crypto/rand/rand.go b/src/crypto/rand/rand.go
index a5ccd19de3..fddd1147e6 100644
--- a/src/crypto/rand/rand.go
+++ b/src/crypto/rand/rand.go
@@ -14,7 +14,7 @@ import "io"
// On Linux and FreeBSD, Reader uses getrandom(2) if available, /dev/urandom otherwise.
// On OpenBSD, Reader uses getentropy(2).
// On other Unix-like systems, Reader reads from /dev/urandom.
-// On Windows systems, Reader uses the CryptGenRandom API.
+// On Windows systems, Reader uses the RtlGenRandom API.
// On Wasm, Reader uses the Web Crypto API.
var Reader io.Reader
@@ -23,7 +23,3 @@ var Reader io.Reader
func Read(b []byte) (n int, err error) {
return io.ReadFull(Reader, b)
}
-
-func warnBlocked() {
- println("crypto/rand: blocked for 60 seconds waiting to read random data from the kernel")
-}
diff --git a/src/crypto/rand/rand_unix.go b/src/crypto/rand/rand_unix.go
index 0610f691b0..548a5e4cb9 100644
--- a/src/crypto/rand/rand_unix.go
+++ b/src/crypto/rand/rand_unix.go
@@ -47,6 +47,10 @@ type devReader struct {
// urandom-style randomness.
var altGetRandom func([]byte) (ok bool)
+func warnBlocked() {
+ println("crypto/rand: blocked for 60 seconds waiting to read random data from the kernel")
+}
+
func (r *devReader) Read(b []byte) (n int, err error) {
if atomic.CompareAndSwapInt32(&r.used, 0, 1) {
// First use of randomness. Start timer to warn about
diff --git a/src/crypto/rand/rand_windows.go b/src/crypto/rand/rand_windows.go
index 78a4ed6d67..8b2c960906 100644
--- a/src/crypto/rand/rand_windows.go
+++ b/src/crypto/rand/rand_windows.go
@@ -9,48 +9,24 @@ package rand
import (
"os"
- "sync"
- "sync/atomic"
"syscall"
- "time"
)
-// Implemented by using Windows CryptoAPI 2.0.
-
func init() { Reader = &rngReader{} }
-// A rngReader satisfies reads by reading from the Windows CryptGenRandom API.
-type rngReader struct {
- used int32 // atomic; whether this rngReader has been used
- prov syscall.Handle
- mu sync.Mutex
-}
+type rngReader struct{}
func (r *rngReader) Read(b []byte) (n int, err error) {
- if atomic.CompareAndSwapInt32(&r.used, 0, 1) {
- // First use of randomness. Start timer to warn about
- // being blocked on entropy not being available.
- t := time.AfterFunc(60*time.Second, warnBlocked)
- defer t.Stop()
- }
- r.mu.Lock()
- if r.prov == 0 {
- const provType = syscall.PROV_RSA_FULL
- const flags = syscall.CRYPT_VERIFYCONTEXT | syscall.CRYPT_SILENT
- err := syscall.CryptAcquireContext(&r.prov, nil, nil, provType, flags)
- if err != nil {
- r.mu.Unlock()
- return 0, os.NewSyscallError("CryptAcquireContext", err)
- }
- }
- r.mu.Unlock()
+ // RtlGenRandom only accepts 2**32-1 bytes at a time, so truncate.
+ inputLen := uint32(len(b))
- if len(b) == 0 {
+ if inputLen == 0 {
return 0, nil
}
- err = syscall.CryptGenRandom(r.prov, uint32(len(b)), &b[0])
+
+ err = syscall.RtlGenRandom(&b[0], inputLen)
if err != nil {
- return 0, os.NewSyscallError("CryptGenRandom", err)
+ return 0, os.NewSyscallError("RtlGenRandom", err)
}
- return len(b), nil
+ return int(inputLen), nil
}
diff --git a/src/crypto/tls/common.go b/src/crypto/tls/common.go
index e4f18bf5eb..66d2c005a7 100644
--- a/src/crypto/tls/common.go
+++ b/src/crypto/tls/common.go
@@ -294,10 +294,26 @@ func (cs *ConnectionState) ExportKeyingMaterial(label string, context []byte, le
type ClientAuthType int
const (
+ // NoClientCert indicates that no client certificate should be requested
+ // during the handshake, and if any certificates are sent they will not
+ // be verified.
NoClientCert ClientAuthType = iota
+ // RequestClientCert indicates that a client certificate should be requested
+ // during the handshake, but does not require that the client send any
+ // certificates.
RequestClientCert
+ // RequireAnyClientCert indicates that a client certificate should be requested
+ // during the handshake, and that at least one certificate is required to be
+ // sent by the client, but that certificate is not required to be valid.
RequireAnyClientCert
+ // VerifyClientCertIfGiven indicates that a client certificate should be requested
+ // during the handshake, but does not require that the client sends a
+ // certificate. If the client does send a certificate it is required to be
+ // valid.
VerifyClientCertIfGiven
+ // RequireAndVerifyClientCert indicates that a client certificate should be requested
+ // during the handshake, and that at least one valid certificate is required
+ // to be sent by the client.
RequireAndVerifyClientCert
)
diff --git a/src/crypto/tls/conn.go b/src/crypto/tls/conn.go
index 5dff76c988..f1d4cb926c 100644
--- a/src/crypto/tls/conn.go
+++ b/src/crypto/tls/conn.go
@@ -168,18 +168,18 @@ type halfConn struct {
trafficSecret []byte // current TLS 1.3 traffic secret
}
-type permamentError struct {
+type permanentError struct {
err net.Error
}
-func (e *permamentError) Error() string { return e.err.Error() }
-func (e *permamentError) Unwrap() error { return e.err }
-func (e *permamentError) Timeout() bool { return e.err.Timeout() }
-func (e *permamentError) Temporary() bool { return false }
+func (e *permanentError) Error() string { return e.err.Error() }
+func (e *permanentError) Unwrap() error { return e.err }
+func (e *permanentError) Timeout() bool { return e.err.Timeout() }
+func (e *permanentError) Temporary() bool { return false }
func (hc *halfConn) setErrorLocked(err error) error {
if e, ok := err.(net.Error); ok {
- hc.err = &permamentError{err: e}
+ hc.err = &permanentError{err: e}
} else {
hc.err = err
}
diff --git a/src/crypto/tls/handshake_test.go b/src/crypto/tls/handshake_test.go
index f55cd16ca8..605be587b5 100644
--- a/src/crypto/tls/handshake_test.go
+++ b/src/crypto/tls/handshake_test.go
@@ -86,7 +86,7 @@ func checkOpenSSLVersion() error {
println("to update the test data.")
println("")
println("Configure it with:")
- println("./Configure enable-weak-ssl-ciphers")
+ println("./Configure enable-weak-ssl-ciphers no-shared")
println("and then add the apps/ directory at the front of your PATH.")
println("***********************************************")
@@ -403,7 +403,7 @@ func testHandshake(t *testing.T, clientConfig, serverConfig *Config) (serverStat
}
defer cli.Close()
clientState = cli.ConnectionState()
- buf, err := ioutil.ReadAll(cli)
+ buf, err := io.ReadAll(cli)
if err != nil {
t.Errorf("failed to call cli.Read: %v", err)
}
diff --git a/src/crypto/tls/tls_test.go b/src/crypto/tls/tls_test.go
index 4ab8a430ba..9995538871 100644
--- a/src/crypto/tls/tls_test.go
+++ b/src/crypto/tls/tls_test.go
@@ -14,7 +14,6 @@ import (
"fmt"
"internal/testenv"
"io"
- "io/ioutil"
"math"
"net"
"os"
@@ -594,7 +593,7 @@ func TestConnCloseWrite(t *testing.T) {
}
defer srv.Close()
- data, err := ioutil.ReadAll(srv)
+ data, err := io.ReadAll(srv)
if err != nil {
return err
}
@@ -635,7 +634,7 @@ func TestConnCloseWrite(t *testing.T) {
return fmt.Errorf("CloseWrite error = %v; want errShutdown", err)
}
- data, err := ioutil.ReadAll(conn)
+ data, err := io.ReadAll(conn)
if err != nil {
return err
}
@@ -698,7 +697,7 @@ func TestWarningAlertFlood(t *testing.T) {
}
defer srv.Close()
- _, err = ioutil.ReadAll(srv)
+ _, err = io.ReadAll(srv)
if err == nil {
return errors.New("unexpected lack of error from server")
}
diff --git a/src/crypto/x509/internal/macos/corefoundation.go b/src/crypto/x509/internal/macos/corefoundation.go
index 359694fabf..a248ee3292 100644
--- a/src/crypto/x509/internal/macos/corefoundation.go
+++ b/src/crypto/x509/internal/macos/corefoundation.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin,amd64
+// +build darwin,!ios
// Package macOS provides cgo-less wrappers for Core Foundation and
// Security.framework, similarly to how package syscall provides access to
diff --git a/src/crypto/x509/internal/macos/corefoundation.s b/src/crypto/x509/internal/macos/corefoundation.s
index 8f6be47e4b..a4495d68dd 100644
--- a/src/crypto/x509/internal/macos/corefoundation.s
+++ b/src/crypto/x509/internal/macos/corefoundation.s
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin,amd64
+// +build darwin,!ios
#include "textflag.h"
diff --git a/src/crypto/x509/internal/macos/security.go b/src/crypto/x509/internal/macos/security.go
index 64fe206390..59cc19c587 100644
--- a/src/crypto/x509/internal/macos/security.go
+++ b/src/crypto/x509/internal/macos/security.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin,amd64
+// +build darwin,!ios
package macOS
diff --git a/src/crypto/x509/internal/macos/security.s b/src/crypto/x509/internal/macos/security.s
index 1630c55bab..bd446dbcbe 100644
--- a/src/crypto/x509/internal/macos/security.s
+++ b/src/crypto/x509/internal/macos/security.s
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin,amd64
+// +build darwin,!ios
#include "textflag.h"
diff --git a/src/crypto/x509/pem_decrypt.go b/src/crypto/x509/pem_decrypt.go
index 93d1e4a922..781cb3de83 100644
--- a/src/crypto/x509/pem_decrypt.go
+++ b/src/crypto/x509/pem_decrypt.go
@@ -95,7 +95,12 @@ func (c rfc1423Algo) deriveKey(password, salt []byte) []byte {
return out
}
-// IsEncryptedPEMBlock returns if the PEM block is password encrypted.
+// IsEncryptedPEMBlock returns whether the PEM block is password encrypted
+// according to RFC 1423.
+//
+// Deprecated: Legacy PEM encryption as specified in RFC 1423 is insecure by
+// design. Since it does not authenticate the ciphertext, it is vulnerable to
+// padding oracle attacks that can let an attacker recover the plaintext.
func IsEncryptedPEMBlock(b *pem.Block) bool {
_, ok := b.Headers["DEK-Info"]
return ok
@@ -104,14 +109,18 @@ func IsEncryptedPEMBlock(b *pem.Block) bool {
// IncorrectPasswordError is returned when an incorrect password is detected.
var IncorrectPasswordError = errors.New("x509: decryption password incorrect")
-// DecryptPEMBlock takes a password encrypted PEM block and the password used to
-// encrypt it and returns a slice of decrypted DER encoded bytes. It inspects
-// the DEK-Info header to determine the algorithm used for decryption. If no
-// DEK-Info header is present, an error is returned. If an incorrect password
-// is detected an IncorrectPasswordError is returned. Because of deficiencies
-// in the encrypted-PEM format, it's not always possible to detect an incorrect
-// password. In these cases no error will be returned but the decrypted DER
-// bytes will be random noise.
+// DecryptPEMBlock takes a PEM block encrypted according to RFC 1423 and the
+// password used to encrypt it and returns a slice of decrypted DER encoded
+// bytes. It inspects the DEK-Info header to determine the algorithm used for
+// decryption. If no DEK-Info header is present, an error is returned. If an
+// incorrect password is detected an IncorrectPasswordError is returned. Because
+// of deficiencies in the format, it's not always possible to detect an
+// incorrect password. In these cases no error will be returned but the
+// decrypted DER bytes will be random noise.
+//
+// Deprecated: Legacy PEM encryption as specified in RFC 1423 is insecure by
+// design. Since it does not authenticate the ciphertext, it is vulnerable to
+// padding oracle attacks that can let an attacker recover the plaintext.
func DecryptPEMBlock(b *pem.Block, password []byte) ([]byte, error) {
dek, ok := b.Headers["DEK-Info"]
if !ok {
@@ -178,8 +187,12 @@ func DecryptPEMBlock(b *pem.Block, password []byte) ([]byte, error) {
}
// EncryptPEMBlock returns a PEM block of the specified type holding the
-// given DER-encoded data encrypted with the specified algorithm and
-// password.
+// given DER encoded data encrypted with the specified algorithm and
+// password according to RFC 1423.
+//
+// Deprecated: Legacy PEM encryption as specified in RFC 1423 is insecure by
+// design. Since it does not authenticate the ciphertext, it is vulnerable to
+// padding oracle attacks that can let an attacker recover the plaintext.
func EncryptPEMBlock(rand io.Reader, blockType string, data, password []byte, alg PEMCipher) (*pem.Block, error) {
ciph := cipherByKey(alg)
if ciph == nil {
diff --git a/src/crypto/x509/root.go b/src/crypto/x509/root.go
index da5e91b91c..eccb64121f 100644
--- a/src/crypto/x509/root.go
+++ b/src/crypto/x509/root.go
@@ -4,7 +4,7 @@
package x509
-//go:generate go run root_darwin_ios_gen.go -version 55161.80.1
+//go:generate go run root_ios_gen.go -version 55161.80.1
import "sync"
diff --git a/src/crypto/x509/root_cgo_darwin_amd64.go b/src/crypto/x509/root_cgo_darwin.go
index 15c72cc0c8..15c72cc0c8 100644
--- a/src/crypto/x509/root_cgo_darwin_amd64.go
+++ b/src/crypto/x509/root_cgo_darwin.go
diff --git a/src/crypto/x509/root_darwin_amd64.go b/src/crypto/x509/root_darwin.go
index ce88de025e..ce88de025e 100644
--- a/src/crypto/x509/root_darwin_amd64.go
+++ b/src/crypto/x509/root_darwin.go
diff --git a/src/crypto/x509/root_darwin_iosx.go b/src/crypto/x509/root_ios.go
index 5ecc4911b3..98e747733a 100644
--- a/src/crypto/x509/root_darwin_iosx.go
+++ b/src/crypto/x509/root_ios.go
@@ -1,7 +1,7 @@
-// Code generated by root_darwin_ios_gen.go -version 55161.80.1; DO NOT EDIT.
+// Code generated by root_ios_gen.go -version 55161.80.1; DO NOT EDIT.
// Update the version in root.go and regenerate with "go generate".
-// +build darwin,arm64 darwin,amd64,ios
+// +build ios
// +build !x509omitbundledroots
package x509
diff --git a/src/crypto/x509/root_darwin_ios_gen.go b/src/crypto/x509/root_ios_gen.go
index 61152b4d11..0641c073ea 100644
--- a/src/crypto/x509/root_darwin_ios_gen.go
+++ b/src/crypto/x509/root_ios_gen.go
@@ -4,7 +4,7 @@
// +build ignore
-// Generates root_darwin_iosx.go.
+// Generates root_ios.go.
//
// As of iOS 13, there is no API for querying the system trusted X.509 root
// certificates.
@@ -37,10 +37,7 @@ import (
)
func main() {
- // Temporarily name the file _iosx.go, to avoid restricting it to GOOS=ios,
- // as this is also used for darwin/arm64 (macOS).
- // TODO: maybe use darwin/amd64 implementation on macOS arm64?
- var output = flag.String("output", "root_darwin_iosx.go", "file name to write")
+ var output = flag.String("output", "root_ios.go", "file name to write")
var version = flag.String("version", "", "security_certificates version")
flag.Parse()
if *version == "" {
@@ -84,7 +81,7 @@ func main() {
continue
}
- der, err := ioutil.ReadAll(tr)
+ der, err := io.ReadAll(tr)
if err != nil {
log.Fatal(err)
}
@@ -159,10 +156,10 @@ func main() {
}
}
-const header = `// Code generated by root_darwin_ios_gen.go -version %s; DO NOT EDIT.
+const header = `// Code generated by root_ios_gen.go -version %s; DO NOT EDIT.
// Update the version in root.go and regenerate with "go generate".
-// +build darwin,arm64 darwin,amd64,ios
+// +build ios
// +build !x509omitbundledroots
package x509
diff --git a/src/crypto/x509/root_unix.go b/src/crypto/x509/root_unix.go
index 2aa38751f3..ae72f025c3 100644
--- a/src/crypto/x509/root_unix.go
+++ b/src/crypto/x509/root_unix.go
@@ -7,6 +7,7 @@
package x509
import (
+ "io/fs"
"io/ioutil"
"os"
"path/filepath"
@@ -83,7 +84,7 @@ func loadSystemRoots() (*CertPool, error) {
// readUniqueDirectoryEntries is like ioutil.ReadDir but omits
// symlinks that point within the directory.
-func readUniqueDirectoryEntries(dir string) ([]os.FileInfo, error) {
+func readUniqueDirectoryEntries(dir string) ([]fs.FileInfo, error) {
fis, err := ioutil.ReadDir(dir)
if err != nil {
return nil, err
@@ -99,8 +100,8 @@ func readUniqueDirectoryEntries(dir string) ([]os.FileInfo, error) {
// isSameDirSymlink reports whether fi in dir is a symlink with a
// target not containing a slash.
-func isSameDirSymlink(fi os.FileInfo, dir string) bool {
- if fi.Mode()&os.ModeSymlink == 0 {
+func isSameDirSymlink(fi fs.FileInfo, dir string) bool {
+ if fi.Mode()&fs.ModeSymlink == 0 {
return false
}
target, err := os.Readlink(filepath.Join(dir, fi.Name()))
diff --git a/src/crypto/x509/x509.go b/src/crypto/x509/x509.go
index 93dca03840..b421d75973 100644
--- a/src/crypto/x509/x509.go
+++ b/src/crypto/x509/x509.go
@@ -159,10 +159,6 @@ type dsaAlgorithmParameters struct {
P, Q, G *big.Int
}
-type dsaSignature struct {
- R, S *big.Int
-}
-
type validity struct {
NotBefore, NotAfter time.Time
}
@@ -182,14 +178,15 @@ type SignatureAlgorithm int
const (
UnknownSignatureAlgorithm SignatureAlgorithm = iota
- MD2WithRSA
- MD5WithRSA
+
+ MD2WithRSA // Unsupported.
+ MD5WithRSA // Only supported for signing, not verification.
SHA1WithRSA
SHA256WithRSA
SHA384WithRSA
SHA512WithRSA
- DSAWithSHA1
- DSAWithSHA256
+ DSAWithSHA1 // Unsupported.
+ DSAWithSHA256 // Unsupported.
ECDSAWithSHA1
ECDSAWithSHA256
ECDSAWithSHA384
@@ -223,7 +220,7 @@ type PublicKeyAlgorithm int
const (
UnknownPublicKeyAlgorithm PublicKeyAlgorithm = iota
RSA
- DSA
+ DSA // Unsupported.
ECDSA
Ed25519
)
@@ -845,28 +842,6 @@ func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey
} else {
return rsa.VerifyPKCS1v15(pub, hashType, signed, signature)
}
- case *dsa.PublicKey:
- if pubKeyAlgo != DSA {
- return signaturePublicKeyAlgoMismatchError(pubKeyAlgo, pub)
- }
- dsaSig := new(dsaSignature)
- if rest, err := asn1.Unmarshal(signature, dsaSig); err != nil {
- return err
- } else if len(rest) != 0 {
- return errors.New("x509: trailing data after DSA signature")
- }
- if dsaSig.R.Sign() <= 0 || dsaSig.S.Sign() <= 0 {
- return errors.New("x509: DSA signature contained zero or negative values")
- }
- // According to FIPS 186-3, section 4.6, the hash must be truncated if it is longer
- // than the key length, but crypto/dsa doesn't do it automatically.
- if maxHashLen := pub.Q.BitLen() / 8; maxHashLen < len(signed) {
- signed = signed[:maxHashLen]
- }
- if !dsa.Verify(pub, signed, dsaSig.R, dsaSig.S) {
- return errors.New("x509: DSA verification failure")
- }
- return
case *ecdsa.PublicKey:
if pubKeyAlgo != ECDSA {
return signaturePublicKeyAlgoMismatchError(pubKeyAlgo, pub)
@@ -2170,12 +2145,26 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv
return
}
- return asn1.Marshal(certificate{
+ signedCert, err := asn1.Marshal(certificate{
nil,
c,
signatureAlgorithm,
asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
})
+ if err != nil {
+ return nil, err
+ }
+
+ // Check the signature to ensure the crypto.Signer behaved correctly.
+ // We skip this check if the signature algorithm is MD5WithRSA as we
+ // only support this algorithm for signing, and not verification.
+ if sigAlg := getSignatureAlgorithmFromAI(signatureAlgorithm); sigAlg != MD5WithRSA {
+ if err := checkSignature(sigAlg, c.Raw, signature, key.Public()); err != nil {
+ return nil, fmt.Errorf("x509: signature over certificate returned by signer is invalid: %w", err)
+ }
+ }
+
+ return signedCert, nil
}
// pemCRLPrefix is the magic string that indicates that we have a PEM encoded
diff --git a/src/crypto/x509/x509_test.go b/src/crypto/x509/x509_test.go
index e87294bde5..47d78cf02a 100644
--- a/src/crypto/x509/x509_test.go
+++ b/src/crypto/x509/x509_test.go
@@ -22,6 +22,7 @@ import (
"encoding/pem"
"fmt"
"internal/testenv"
+ "io"
"math/big"
"net"
"net/url"
@@ -988,51 +989,8 @@ func TestVerifyCertificateWithDSASignature(t *testing.T) {
t.Fatalf("Failed to parse certificate: %s", err)
}
// test cert is self-signed
- if err = cert.CheckSignatureFrom(cert); err != nil {
- t.Fatalf("DSA Certificate verification failed: %s", err)
- }
-}
-
-const dsaCert1024WithSha256 = `-----BEGIN CERTIFICATE-----
-MIIDKzCCAumgAwIBAgIUOXWPK4gTRZVVY7OSXTU00QEWQU8wCwYJYIZIAWUDBAMC
-MEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJ
-bnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwIBcNMTkxMDAxMDYxODUyWhgPMzAxOTAy
-MDEwNjE4NTJaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
-HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggG4MIIBLAYHKoZIzjgE
-ATCCAR8CgYEAr79m/1ypU1aUbbLX1jikTyX7w2QYP+EkxNtXUiiTuxkC1KBqqxT3
-0Aht2vxFR47ODEK4B79rHO+UevhaqDaAHSH7Z/9umS0h0aS32KLDLb+LI5AneCrn
-eW5YbVhfD03N7uR4kKUCKOnWj5hAk9xiE3y7oFR0bBXzqrrHJF9LMd0CFQCB6lSj
-HSW0rGmNxIZsBl72u7JFLQKBgQCOFd1PGEQmddn0cdFgby5QQfjrqmoD1zNlFZEt
-L0x1EbndFwelLlF1ChNh3NPNUkjwRbla07FDlONs1GMJq6w4vW11ns+pUvAZ2+RM
-EVFjugip8az2ncn3UujGTVdFxnSTLBsRlMP/tFDK3ky//8zn/5ha9SKKw4v1uv6M
-JuoIbwOBhQACgYEAoeKeR90nwrnoPi5MOUPBLQvuzB87slfr+3kL8vFCmgjA6MtB
-7TxQKoBTOo5aVgWDp0lMIMxLd6btzBrm6r3VdRlh/cL8/PtbxkFwBa+Upe4o5NAh
-ISCe2/f2leT1PxtF8xxYjz/fszeUeHsJbVMilE2cuB2SYrR5tMExiqy+QpqjUzBR
-MB0GA1UdDgQWBBQDMIEL8Z3jc1d9wCxWtksUWc8RkjAfBgNVHSMEGDAWgBQDMIEL
-8Z3jc1d9wCxWtksUWc8RkjAPBgNVHRMBAf8EBTADAQH/MAsGCWCGSAFlAwQDAgMv
-ADAsAhQFehZgI4OyKBGpfnXvyJ0Z/0a6nAIUTO265Ane87LfJuQr3FrqvuCI354=
------END CERTIFICATE-----
-`
-
-func TestVerifyCertificateWithDSATooLongHash(t *testing.T) {
- pemBlock, _ := pem.Decode([]byte(dsaCert1024WithSha256))
- cert, err := ParseCertificate(pemBlock.Bytes)
- if err != nil {
- t.Fatalf("Failed to parse certificate: %s", err)
- }
-
- // test cert is self-signed
- if err = cert.CheckSignatureFrom(cert); err != nil {
- t.Fatalf("DSA Certificate self-signature verification failed: %s", err)
- }
-
- signed := []byte("A wild Gopher appears!\n")
- signature, _ := hex.DecodeString("302c0214417aca7ff458f5b566e43e7b82f994953da84be50214625901e249e33f4e4838f8b5966020c286dd610e")
-
- // This signature is using SHA256, but only has 1024 DSA key. The hash has to be truncated
- // in CheckSignature, otherwise it won't pass.
- if err = cert.CheckSignature(DSAWithSHA256, signed, signature); err != nil {
- t.Fatalf("DSA signature verification failed: %s", err)
+ if err = cert.CheckSignatureFrom(cert); err == nil {
+ t.Fatalf("Expected error verifying DSA certificate")
}
}
@@ -2863,3 +2821,94 @@ func TestIA5SANEnforcement(t *testing.T) {
}
}
}
+
+func BenchmarkCreateCertificate(b *testing.B) {
+ template := &Certificate{
+ SerialNumber: big.NewInt(10),
+ DNSNames: []string{"example.com"},
+ }
+ tests := []struct {
+ name string
+ gen func() crypto.Signer
+ }{
+ {
+ name: "RSA 2048",
+ gen: func() crypto.Signer {
+ k, err := rsa.GenerateKey(rand.Reader, 2048)
+ if err != nil {
+ b.Fatalf("failed to generate test key: %s", err)
+ }
+ return k
+ },
+ },
+ {
+ name: "ECDSA P256",
+ gen: func() crypto.Signer {
+ k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ b.Fatalf("failed to generate test key: %s", err)
+ }
+ return k
+ },
+ },
+ }
+
+ for _, tc := range tests {
+ k := tc.gen()
+ b.ResetTimer()
+ b.Run(tc.name, func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ _, err := CreateCertificate(rand.Reader, template, template, k.Public(), k)
+ if err != nil {
+ b.Fatalf("failed to create certificate: %s", err)
+ }
+ }
+ })
+ }
+}
+
+type brokenSigner struct {
+ pub crypto.PublicKey
+}
+
+func (bs *brokenSigner) Public() crypto.PublicKey {
+ return bs.pub
+}
+
+func (bs *brokenSigner) Sign(_ io.Reader, _ []byte, _ crypto.SignerOpts) ([]byte, error) {
+ return []byte{1, 2, 3}, nil
+}
+
+func TestCreateCertificateBrokenSigner(t *testing.T) {
+ template := &Certificate{
+ SerialNumber: big.NewInt(10),
+ DNSNames: []string{"example.com"},
+ }
+ k, err := rsa.GenerateKey(rand.Reader, 1024)
+ if err != nil {
+ t.Fatalf("failed to generate test key: %s", err)
+ }
+ expectedErr := "x509: signature over certificate returned by signer is invalid: crypto/rsa: verification error"
+ _, err = CreateCertificate(rand.Reader, template, template, k.Public(), &brokenSigner{k.Public()})
+ if err == nil {
+ t.Fatal("expected CreateCertificate to fail with a broken signer")
+ } else if err.Error() != expectedErr {
+ t.Fatalf("CreateCertificate returned an unexpected error: got %q, want %q", err, expectedErr)
+ }
+}
+
+func TestCreateCertificateMD5(t *testing.T) {
+ template := &Certificate{
+ SerialNumber: big.NewInt(10),
+ DNSNames: []string{"example.com"},
+ SignatureAlgorithm: MD5WithRSA,
+ }
+ k, err := rsa.GenerateKey(rand.Reader, 1024)
+ if err != nil {
+ t.Fatalf("failed to generate test key: %s", err)
+ }
+ _, err = CreateCertificate(rand.Reader, template, template, k.Public(), &brokenSigner{k.Public()})
+ if err != nil {
+ t.Fatalf("CreateCertificate failed when SignatureAlgorithm = MD5WithRSA: %s", err)
+ }
+}