]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.go1.19] crypto/x509: return typed verification errors on macOS
authorRoland Shoemaker <roland@golang.org>
Tue, 22 Nov 2022 00:47:39 +0000 (16:47 -0800)
committerGopher Robot <gobot@golang.org>
Fri, 6 Jan 2023 17:52:33 +0000 (17:52 +0000)
On macOS return the error code from SecTrustEvaluateWithError, and use
it to create typed errors that can be returned from Verify.

Updates #56891
Fixes #57427

Change-Id: Ib597ce202abb60702f730e75da583894422e4c14
Reviewed-on: https://go-review.googlesource.com/c/go/+/452620
Run-TryBot: Roland Shoemaker <roland@golang.org>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
(cherry picked from commit c9a10d48a8f0e8479f5b9d98c5bd81b64a90d23d)
Reviewed-on: https://go-review.googlesource.com/c/go/+/460895
Run-TryBot: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Heschi Kreinick <heschi@google.com>
Auto-Submit: Heschi Kreinick <heschi@google.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
src/crypto/x509/internal/macos/corefoundation.go
src/crypto/x509/internal/macos/corefoundation.s
src/crypto/x509/internal/macos/security.go
src/crypto/x509/root_darwin.go
src/crypto/x509/root_darwin_test.go

index 2677ff706ae33acd6e904fa4d8375518191c3d13..eed99e6197fe2778b71eb2def366864cdd74751e 100644 (file)
@@ -188,6 +188,13 @@ func CFErrorCopyDescription(errRef CFRef) CFRef {
 }
 func x509_CFErrorCopyDescription_trampoline()
 
+//go:cgo_import_dynamic x509_CFErrorGetCode CFErrorGetCode "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
+
+func CFErrorGetCode(errRef CFRef) int {
+       return int(syscall(abi.FuncPCABI0(x509_CFErrorGetCode_trampoline), uintptr(errRef), 0, 0, 0, 0, 0))
+}
+func x509_CFErrorGetCode_trampoline()
+
 //go:cgo_import_dynamic x509_CFStringCreateExternalRepresentation CFStringCreateExternalRepresentation "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
 
 func CFStringCreateExternalRepresentation(strRef CFRef) (CFRef, error) {
index d69f72f795cd949504851c32a9b4be7599076f59..49cd084467b2c396e22cb2a06c983c6966dc8d7c 100644 (file)
@@ -37,5 +37,7 @@ TEXT ·x509_CFDataCreate_trampoline(SB),NOSPLIT,$0-0
        JMP x509_CFDataCreate(SB)
 TEXT ·x509_CFErrorCopyDescription_trampoline(SB),NOSPLIT,$0-0
        JMP x509_CFErrorCopyDescription(SB)
+TEXT ·x509_CFErrorGetCode_trampoline(SB),NOSPLIT,$0-0
+       JMP x509_CFErrorGetCode(SB)
 TEXT ·x509_CFStringCreateExternalRepresentation_trampoline(SB),NOSPLIT,$0-0
        JMP x509_CFStringCreateExternalRepresentation(SB)
index d8147ba8ba26bc01f3a9b70fd0b189c44ea89cc6..cf9df2beacea0dc82e5dc1f43093d753ac4005e8 100644 (file)
@@ -8,7 +8,6 @@ package macOS
 
 import (
        "errors"
-       "fmt"
        "internal/abi"
        "strconv"
        "unsafe"
@@ -52,6 +51,15 @@ const (
        SecTrustSettingsDomainSystem
 )
 
+const (
+       // various macOS error codes that can be returned from
+       // SecTrustEvaluateWithError that we can map to Go cert
+       // verification error types.
+       ErrSecCertificateExpired = -67818
+       ErrSecHostNameMismatch   = -67602
+       ErrSecNotTrusted         = -67843
+)
+
 type OSStatus struct {
        call   string
        status int32
@@ -196,17 +204,18 @@ func x509_SecTrustGetResult_trampoline()
 
 //go:cgo_import_dynamic x509_SecTrustEvaluateWithError SecTrustEvaluateWithError "/System/Library/Frameworks/Security.framework/Versions/A/Security"
 
-func SecTrustEvaluateWithError(trustObj CFRef) error {
+func SecTrustEvaluateWithError(trustObj CFRef) (int, error) {
        var errRef CFRef
        ret := syscall(abi.FuncPCABI0(x509_SecTrustEvaluateWithError_trampoline), uintptr(trustObj), uintptr(unsafe.Pointer(&errRef)), 0, 0, 0, 0)
        if int32(ret) != 1 {
                errStr := CFErrorCopyDescription(errRef)
-               err := fmt.Errorf("x509: %s", CFStringToString(errStr))
+               err := errors.New(CFStringToString(errStr))
+               errCode := CFErrorGetCode(errRef)
                CFRelease(errRef)
                CFRelease(errStr)
-               return err
+               return errCode, err
        }
-       return nil
+       return 0, nil
 }
 func x509_SecTrustEvaluateWithError_trampoline()
 
index 47594626537d06b7811cd2c98c249dbec9f9c60f..8dfd1aaefda1368b58fefbf16fe0e515f0a57772 100644 (file)
@@ -7,6 +7,7 @@ package x509
 import (
        macOS "crypto/x509/internal/macos"
        "errors"
+       "fmt"
 )
 
 func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
@@ -54,8 +55,17 @@ func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate
        // always enforce its SCT requirements, and there are still _some_ people
        // using TLS or OCSP for that.
 
-       if err := macOS.SecTrustEvaluateWithError(trustObj); err != nil {
-               return nil, err
+       if ret, err := macOS.SecTrustEvaluateWithError(trustObj); err != nil {
+               switch ret {
+               case macOS.ErrSecCertificateExpired:
+                       return nil, CertificateInvalidError{c, Expired, err.Error()}
+               case macOS.ErrSecHostNameMismatch:
+                       return nil, HostnameError{c, opts.DNSName}
+               case macOS.ErrSecNotTrusted:
+                       return nil, UnknownAuthorityError{Cert: c}
+               default:
+                       return nil, fmt.Errorf("x509: %s", err)
+               }
        }
 
        chain := [][]*Certificate{{}}
index 90a464f624960a75bd39d390d7e1d492a499a511..299cecf5563f682a2f18f1d51b440c0329d7b41c 100644 (file)
@@ -42,23 +42,23 @@ func TestPlatformVerifier(t *testing.T) {
                {
                        name:        "expired leaf",
                        host:        "expired.badssl.com",
-                       expectedErr: "x509: “*.badssl.com” certificate is expired",
+                       expectedErr: "x509: certificate has expired or is not yet valid: “*.badssl.com” certificate is expired",
                },
                {
                        name:        "wrong host for leaf",
                        host:        "wrong.host.badssl.com",
                        verifyName:  "wrong.host.badssl.com",
-                       expectedErr: "x509: “*.badssl.com” certificate name does not match input",
+                       expectedErr: "x509: certificate is valid for *.badssl.com, badssl.com, not wrong.host.badssl.com",
                },
                {
                        name:        "self-signed leaf",
                        host:        "self-signed.badssl.com",
-                       expectedErr: "x509: “*.badssl.com” certificate is not trusted",
+                       expectedErr: "x509: certificate signed by unknown authority",
                },
                {
                        name:        "untrusted root",
                        host:        "untrusted-root.badssl.com",
-                       expectedErr: "x509: “BadSSL Untrusted Root Certificate Authority” certificate is not trusted",
+                       expectedErr: "x509: certificate signed by unknown authority",
                },
                {
                        name:        "revoked leaf",
@@ -74,7 +74,7 @@ func TestPlatformVerifier(t *testing.T) {
                        name:        "expired leaf (custom time)",
                        host:        "google.com",
                        verifyTime:  time.Time{}.Add(time.Hour),
-                       expectedErr: "x509: “*.google.com” certificate is expired",
+                       expectedErr: "x509: certificate has expired or is not yet valid: “*.google.com” certificate is expired",
                },
                {
                        name:       "valid chain (custom time)",