Repository: go
Issue: crypto: Many APIs return errors caused by other errors, without allowing unwrapping
Labels: NeedsInvestigation

### What version of Go are you using (`go version`)?

<pre>
$ go version
go version go1.20 darwin/amd64
</pre>

### Does this issue reproduce with the latest release?
Yes.

### What operating system and processor architecture are you using (`go env`)?

<details><summary><code>go env</code> Output</summary><br><pre>
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/me/Library/Caches/go-build"
GOENV="/Users/me/Library/Application Support/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/me/go/pkg/mod"
GONOPROXY="redacted"
GONOSUMDB="redacted"
GOOS="darwin"
GOPATH="/Users/me/go"
GOPRIVATE="redacted"
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"
GOVCS=""
GOVERSION="go1.20"
GCCGO="gccgo"
GOAMD64="v1"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/dev/null"
GOWORK=""
CGO_CFLAGS="-O2 -g"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-O2 -g"
CGO_FFLAGS="-O2 -g"
CGO_LDFLAGS="-O2 -g"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch x86_64 -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/vd/0rnst0yj2md0t7ss9__mr1540000gs/T/go-build2389605252=/tmp/go-build -gno-record-gcc-switches -fno-common"
</pre></details>

### What did you do?
Attempted to check errors for specific certificate issues in errors returned from `tls.Conn.Read()`.

### What did you expect to see?
`error`s that could be unwrapped to expose child `error`s.


### What did you see instead?
`error`s flattened to strings, so the only solution was to parse the error value.

----

I have an existing PR to wrap child errors rather than flatten them to strings: #58299.

Here are some notes about each of those changes (as requested):

----

All of these would happen during the TLS client connection handshake:

* src/crypto/tls/handshake_client_tls13.go:499
  * Returns from:
    * `crypto/tls.Conn.Read()` (for client connections)
  * Error source:
    * Private function `tls.verifyHandshakeSignature()`
      * `crypto/rsa.VerifyPKCS1v15()`
      * `crypto/rsa.VerifyPSS()`
      * Many of of its errors (currently) are from `errors.New()` or `fmt.Errorf()` with no wrapped errors or specific `error` types.
* src/crypto/tls/handshake_client_tls13.go:610
  * Returns from:
    * `crypto/tls.Conn.Read()` (for client connections)
  * Error source:
    * `tls/Certificate.PrivateKey.(crypto.Signer).Sign()` (for client certificate)

* src/crypto/tls/handshake_client.go:111
  * Returns from:
    * `crypto/tls.Conn.Read()` (for client connections)
  * Error source:
    * Reading the random source (`io.Reader`; default is `crypto/rand.Reader`)
* src/crypto/tls/handshake_client.go:118
  * Returns from:
    * `crypto/tls.Conn.Read()` (for client connections)
  * Error source:
    * Reading the random source (`io.Reader`; default is `crypto/rand.Reader`)
* src/crypto/tls/handshake_client.go:652
  * Returns from:
    * `crypto/tls.Conn.Read()` (for client connections)
  * Error source:
    * `io.Writer` failure on `tls.Config.KeyLogWriter`, if set (which it is not, by default)
* src/crypto/tls/handshake_client.go:858
  * Returns from:
    * `crypto/tls.Conn.Read()` (for client connections)
  * Error source:
    * `crypto/x509.ParseCertificate()`

----

All of these would happen during the TLS server connection handshake:

* src/crypto/tls/ticket.go:137
  * Returns from:
    * `crypto/tls.Conn.HandshakeContext()` (for server connections)
  * Error source:
    * `crypto/aes.NewCipher()`

* src/crypto/tls/handshake_server_tls13.go:641
  * Returns from:
    * `crypto/tls.Conn.HandshakeContext()` (for server connections)
  * Error source:
    * `tls/Certificate.PrivateKey.(crypto.Signer).Sign()` (for server certificate)
* src/crypto/tls/handshake_server_tls13.go:844
  * Returns from:
    * `crypto/tls.Conn.HandshakeContext()` (for server connections)
  * Error source:
    * Private function `tls.verifyHandshakeSignature()`
      * `crypto/rsa.VerifyPKCS1v15()`
      * `crypto/rsa.VerifyPSS()`
      * Many of of its errors (currently) are from `errors.New()` or `fmt.Errorf()` with no wrapped errors or specific `error` types.

* src/crypto/tls/handshake_server.go:673
  * Returns from:
    * `crypto/tls.Conn.HandshakeContext()` (for server connections)
  * Error source:
    * Private function `tls.verifyHandshakeSignature()`
      * `crypto/rsa.VerifyPKCS1v15()`
      * `crypto/rsa.VerifyPSS()`
      * Many of of its errors (currently) are from `errors.New()` or `fmt.Errorf()` with no wrapped errors or specific `error` types.
* src/crypto/tls/handshake_server.go:810
  * Returns from:
    * `crypto/tls.Conn.HandshakeContext()` (for server connections)
  * Error source:
    * `crypto/x509.ParseCertificate()`

----

* src/crypto/tls/key_agreement.go:235
  * Returns from:
    * `crypto/tls.Conn.HandshakeContext()` (for server connections)
  * Error source:
    * `tls/Certificate.PrivateKey.(crypto.Signer).Sign()` (for server certificate)
* src/crypto/tls/key_agreement.go:335
  * Returns from:
    * `crypto/tls.Conn.Read()` (for client connections)
    * `crypto/tls.Conn.HandshakeContext()` (for client connections)
  * Error source:
    * Private function `tls.verifyHandshakeSignature()`
      * `crypto/rsa.VerifyPKCS1v15()`
      * `crypto/rsa.VerifyPSS()`
      * Many of of its errors (currently) are from `errors.New()` or `fmt.Errorf()` with no wrapped errors or specific `error` types.

----

* src/crypto/x509/x509.go:2026
  * Returns from:
    * `crypto/x509.CreateCertificateRequest()`
  * Error source:
    * `encoding/asn1.Marshal()`

* src/crypto/x509/sec1.go:93
  * Returns from:
    * `crypto/x509.ParsePKCS8PrivateKey()`
  * Error source:
    * `encoding/asn1.Unmarshal()`

* src/crypto/x509/pkcs8.go:50
  * Returns from:
    * `crypto/x509.ParsePKCS8PrivateKey()`
  * Error source:
    * `crypto/x509.ParsePKCS1PrivateKey()`
* src/crypto/x509/pkcs8.go:62
  * Returns from:
    * `crypto/x509.ParsePKCS8PrivateKey()`
  * Error source:
    * Private function `x509.parseECPrivateKey()`
      * `encoding/asn1.Unmarshal()`
      * Many of of its errors (currently) are from `errors.New()` or `fmt.Errorf()` with no wrapped errors or specific `error` types.
* src/crypto/x509/pkcs8.go:119
  * Returns from:
    * `crypto/x509.MarshalPKCS8PrivateKey()`
  * Error source:
    * `encoding/asn1.Marshal()`
* src/crypto/x509/pkcs8.go:128
  * Returns from:
    * `crypto/x509.MarshalPKCS8PrivateKey()`
  * Error source:
    * Private function `marshalECPrivateKeyWithOID()`
      * `encoding/asn1.Marshal()`
      * An error from `errors.New()` with no specific `error` type.
* src/crypto/x509/pkcs8.go:157
  * Returns from:
    * `crypto/x509.MarshalPKCS8PrivateKey()`
  * Error source:
    * `encoding/asn1.Marshal()`
* src/crypto/x509/pkcs8.go:166
  * Returns from:
    * `crypto/x509.MarshalPKCS8PrivateKey()`
  * Error source:
    * `encoding/asn1.Marshal()`

* src/crypto/x509/parser.go:538
  * Returns from:
    * `crypto/x509.ParseCertificate()`
    * `crypto/x509.ParseCertificates()`
  * Error source:
    * Private function `isIA5String()`
      * An error from `errors.New()` with no specific `error` type.
* src/crypto/x509/parser.go:580
  * Returns from:
    * `crypto/x509.ParseCertificate()`
    * `crypto/x509.ParseCertificates()`
  * Error source:
    * Private function `isIA5String()`
      * An error from `errors.New()` with no specific `error` type.
* src/crypto/x509/parser.go:604
  * Returns from:
    * `crypto/x509.ParseCertificate()`
    * `crypto/x509.ParseCertificates()`
  * Error source:
    * Private function `isIA5String()`
      * An error from `errors.New()` with no specific `error` type.

* src/crypto/x509/pem_decrypt.go:203
  * Returns from:
    * `crypto/x509.EncryptPEMBlock()`
  * Error source:
    * Reading from the random source (`io.Reader`) provided to `x509.EncryptPEMBlock()`