Update dependencies

This commit is contained in:
bluepython508
2024-11-01 17:33:34 +00:00
parent 033ac0b400
commit 5cdfab398d
3596 changed files with 1033483 additions and 259 deletions

87
vendor/github.com/tailscale/certstore/.appveyor.yml generated vendored Normal file
View File

@@ -0,0 +1,87 @@
skip_branch_with_pr: true
os: "Visual Studio 2015"
build: off
environment:
matrix:
- # Default Go, x64
ARCH: x64
MSYS2_ARCH: x86_64
MSYS2_DIR: msys64
MSYSTEM: MINGW64
GOPATH: c:\gopath
GOROOT: c:\go
GOARCH: amd64
EXTLD: x86_64-w64-mingw32-gcc
- # Default Go, x86
ARCH: x86
MSYS2_ARCH: i686
MSYS2_DIR: msys64
MSYSTEM: MINGW32
GOPATH: c:\gopath
GOROOT: c:\go-x86
GOARCH: 386
EXTLD: i686-w64-mingw32-gcc
- # Go 1.12, x64
ARCH: x64
MSYS2_ARCH: x86_64
MSYS2_DIR: msys64
MSYSTEM: MINGW64
GOPATH: c:\gopath
GOROOT: c:\go112
GOARCH: amd64
EXTLD: x86_64-w64-mingw32-gcc
- # Go 1.11, x64
ARCH: x64
MSYS2_ARCH: x86_64
MSYS2_DIR: msys64
MSYSTEM: MINGW64
GOPATH: c:\gopath
GOROOT: c:\go111
GOARCH: amd64
EXTLD: x86_64-w64-mingw32-gcc
- # Go 1.10, x64
ARCH: x64
MSYS2_ARCH: x86_64
MSYS2_DIR: msys64
MSYSTEM: MINGW64
GOPATH: c:\gopath
GOROOT: c:\go110
GOARCH: amd64
EXTLD: x86_64-w64-mingw32-gcc
- # Go 1.9, x64
ARCH: x64
MSYS2_ARCH: x86_64
MSYS2_DIR: msys64
MSYSTEM: MINGW64
GOPATH: c:\gopath
GOROOT: c:\go19
GOARCH: amd64
EXTLD: x86_64-w64-mingw32-gcc
- # Go 1.9, x64
ARCH: x64
MSYS2_ARCH: x86_64
MSYS2_DIR: msys64
MSYSTEM: MINGW64
GOPATH: c:\gopath
GOROOT: c:\go18
GOARCH: amd64
EXTLD: x86_64-w64-mingw32-gcc
clone_folder: C:\gopath\src\github.com\github\certstore
before_test:
# Ensure CGO is enabled
- set CGO_ENABLED=1
# Go paths
- set PATH=%GOROOT%\bin;C:\%GOPATH%\bin;%PATH%
# MSYS paths
- set PATH=C:\%MSYS2_DIR%\%MSYSTEM%\bin;C:\%MSYS2_DIR%\usr\bin;%PATH%
# Install build deps
- bash -lc "for n in `seq 1 3`; do pacman --noconfirm -S mingw-w64-%MSYS2_ARCH%-libtool && break || sleep 15; done"
# Install Go deps
- go get -t -v ./...
test_script:
- go test -v ./...

21
vendor/github.com/tailscale/certstore/LICENSE.md generated vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Ben Toews.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

98
vendor/github.com/tailscale/certstore/README.md generated vendored Normal file
View File

@@ -0,0 +1,98 @@
# certstore
Certstore is a Go library for accessing user identities stored in platform certificate stores. On Windows and macOS, certstore can enumerate user identities and sign messages with their private keys.
## Fork from original module
This is a fork from the [cyolosecurity fork](https://github.com/cyolosecurity/certstore/)
of the the original [certstore module](https://github.com/github/certstore/). The cyolosecurity
fork adds some functionality that we require (RSA-PSS support and ability to use the machine
certificate store instead of the current user certificate store). However, the cyolosecurity
fork did not update the module name, so we are unable to import it directly, thus leading to
the Tailscale fork.
As of this writing, the [RSA-PSS PR](https://github.com/github/certstore/pull/18) has been
under review for several months and the machine certificate store change has not yet been sent
to the github maintainer for review. Ideally these changes will make their way back into the
original module and we can
[discontinue this fork](https://github.com/tailscale/tailscale/issues/2005) at some point in
the future.
## Example
```go
package main
import (
"crypto"
"encoding/hex"
"errors"
"fmt"
"crypto/rand"
"crypto/sha256"
"github.com/github/certstore"
)
func main() {
sig, err := signWithMyIdentity("Ben Toews", "hello, world!")
if err != nil {
panic(err)
}
fmt.Println(hex.EncodeToString(sig))
}
func signWithMyIdentity(cn, msg string) ([]byte, error) {
// Open the certificate store for use. This must be Close()'ed once you're
// finished with the store and any identities it contains.
store, err := certstore.Open()
if err != nil {
return nil, err
}
defer store.Close()
// Get an Identity slice, containing every identity in the store. Each of
// these must be Close()'ed when you're done with them.
idents, err := store.Identities()
if err != nil {
return nil, err
}
// Iterate through the identities, looking for the one we want.
var me certstore.Identity
for _, ident := range idents {
defer ident.Close()
crt, errr := ident.Certificate()
if errr != nil {
return nil, errr
}
if crt.Subject.CommonName == "Ben Toews" {
me = ident
}
}
if me == nil {
return nil, errors.New("Couldn't find my identity")
}
// Get a crypto.Signer for the identity.
signer, err := me.Signer()
if err != nil {
return nil, err
}
// Digest and sign our message.
digest := sha256.Sum256([]byte(msg))
signature, err := signer.Sign(rand.Reader, digest[:], crypto.SHA256)
if err != nil {
return nil, err
}
return signature, nil
}
```

71
vendor/github.com/tailscale/certstore/certstore.go generated vendored Normal file
View File

@@ -0,0 +1,71 @@
package certstore
import (
"crypto"
"crypto/x509"
"errors"
)
var (
// ErrUnsupportedHash is returned by Signer.Sign() when the provided hash
// algorithm isn't supported.
ErrUnsupportedHash = errors.New("unsupported hash algorithm")
)
// StoreLocation defines the store location to look certificates in.
type StoreLocation int
const (
// User is the user scoped certificate store. "CURRENT_USER" on Windows or
// "login" on MacOS
User StoreLocation = iota
// System is the system scoped certificate store. "LOCAL_MACHINE" on Windows
// or "System" on MacOS
System
)
// StorePermission defines the store permission to open the store with
type StorePermission int
const (
// ReadOnly is the store permission allows reading and using certificates
ReadOnly StorePermission = iota
// ReadWrite is the store permission that allows importing certificates
ReadWrite
)
// Open opens the system's certificate store.
func Open(location StoreLocation, permissions ...StorePermission) (Store, error) {
return openStore(location, permissions...)
}
// Store represents the system's certificate store.
type Store interface {
// Identities gets a list of identities from the store.
Identities() ([]Identity, error)
// Import imports a PKCS#12 (PFX) blob containing a certificate and private
// key.
Import(data []byte, password string) error
// Close closes the store.
Close()
}
// Identity is a X.509 certificate and its corresponding private key.
type Identity interface {
// Certificate gets the identity's certificate.
Certificate() (*x509.Certificate, error)
// CertificateChain attempts to get the identity's full certificate chain.
CertificateChain() ([]*x509.Certificate, error)
// Signer gets a crypto.Signer that uses the identity's private key.
Signer() (crypto.Signer, error)
// Delete deletes this identity from the system.
Delete() error
// Close any manually managed memory held by the Identity.
Close()
}

View File

@@ -0,0 +1,497 @@
package certstore
/*
#cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -framework CoreFoundation -framework Security
#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>
*/
import "C"
import (
"crypto"
"crypto/ecdsa"
"crypto/rsa"
"crypto/x509"
"errors"
"fmt"
"io"
"unsafe"
)
// work around https://golang.org/doc/go1.10#cgo
// in go>=1.10 CFTypeRefs are translated to uintptrs instead of pointers.
var (
nilCFDictionaryRef C.CFDictionaryRef
nilSecCertificateRef C.SecCertificateRef
nilCFArrayRef C.CFArrayRef
nilCFDataRef C.CFDataRef
nilCFErrorRef C.CFErrorRef
nilCFStringRef C.CFStringRef
nilSecIdentityRef C.SecIdentityRef
nilSecKeyRef C.SecKeyRef
nilCFAllocatorRef C.CFAllocatorRef
)
// macStore is a bogus type. We have to explicitly open/close the store on
// windows, so we provide those methods here too.
type macStore int
// openStore is a function for opening a macStore.
func openStore(_ StoreLocation, _ ...StorePermission) (macStore, error) {
return macStore(0), nil
}
// Identities implements the Store interface.
func (s macStore) Identities() ([]Identity, error) {
query := mapToCFDictionary(map[C.CFTypeRef]C.CFTypeRef{
C.CFTypeRef(C.kSecClass): C.CFTypeRef(C.kSecClassIdentity),
C.CFTypeRef(C.kSecReturnRef): C.CFTypeRef(C.kCFBooleanTrue),
C.CFTypeRef(C.kSecMatchLimit): C.CFTypeRef(C.kSecMatchLimitAll),
})
if query == nilCFDictionaryRef {
return nil, errors.New("error creating CFDictionary")
}
defer C.CFRelease(C.CFTypeRef(query))
var absResult C.CFTypeRef
if err := osStatusError(C.SecItemCopyMatching(query, &absResult)); err != nil {
if err == errSecItemNotFound {
return []Identity{}, nil
}
return nil, err
}
defer C.CFRelease(C.CFTypeRef(absResult))
// don't need to release aryResult since the abstract result is released above.
aryResult := C.CFArrayRef(absResult)
// identRefs aren't owned by us initially. newMacIdentity retains them.
n := C.CFArrayGetCount(aryResult)
identRefs := make([]C.CFTypeRef, n)
C.CFArrayGetValues(aryResult, C.CFRange{0, n}, (*unsafe.Pointer)(unsafe.Pointer(&identRefs[0])))
idents := make([]Identity, 0, n)
for _, identRef := range identRefs {
idents = append(idents, newMacIdentity(C.SecIdentityRef(identRef)))
}
return idents, nil
}
// Import implements the Store interface.
func (s macStore) Import(data []byte, password string) error {
cdata, err := bytesToCFData(data)
if err != nil {
return err
}
defer C.CFRelease(C.CFTypeRef(cdata))
cpass := stringToCFString(password)
defer C.CFRelease(C.CFTypeRef(cpass))
cops := mapToCFDictionary(map[C.CFTypeRef]C.CFTypeRef{
C.CFTypeRef(C.kSecImportExportPassphrase): C.CFTypeRef(cpass),
})
if cops == nilCFDictionaryRef {
return errors.New("error creating CFDictionary")
}
defer C.CFRelease(C.CFTypeRef(cops))
var cret C.CFArrayRef
if err := osStatusError(C.SecPKCS12Import(cdata, cops, &cret)); err != nil {
return err
}
defer C.CFRelease(C.CFTypeRef(cret))
return nil
}
// Close implements the Store interface.
func (s macStore) Close() {}
// macIdentity implements the Identity interface.
type macIdentity struct {
ref C.SecIdentityRef
kref C.SecKeyRef
cref C.SecCertificateRef
crt *x509.Certificate
chain []*x509.Certificate
}
func newMacIdentity(ref C.SecIdentityRef) *macIdentity {
C.CFRetain(C.CFTypeRef(ref))
return &macIdentity{ref: ref}
}
// Certificate implements the Identity interface.
func (i *macIdentity) Certificate() (*x509.Certificate, error) {
certRef, err := i.getCertRef()
if err != nil {
return nil, err
}
crt, err := exportCertRef(certRef)
if err != nil {
return nil, err
}
i.crt = crt
return i.crt, nil
}
// CertificateChain implements the Identity interface.
func (i *macIdentity) CertificateChain() ([]*x509.Certificate, error) {
if i.chain != nil {
return i.chain, nil
}
certRef, err := i.getCertRef()
if err != nil {
return nil, err
}
policy := C.SecPolicyCreateSSL(0, nilCFStringRef)
var trustRef C.SecTrustRef
if err := osStatusError(C.SecTrustCreateWithCertificates(C.CFTypeRef(certRef), C.CFTypeRef(policy), &trustRef)); err != nil {
return nil, err
}
defer C.CFRelease(C.CFTypeRef(trustRef))
var status C.SecTrustResultType
if err := osStatusError(C.SecTrustEvaluate(trustRef, &status)); err != nil {
return nil, err
}
var (
nchain = C.SecTrustGetCertificateCount(trustRef)
chain = make([]*x509.Certificate, 0, int(nchain))
)
for i := C.CFIndex(0); i < nchain; i++ {
// TODO: do we need to release these?
chainCertref := C.SecTrustGetCertificateAtIndex(trustRef, i)
if chainCertref == nilSecCertificateRef {
return nil, errors.New("nil certificate in chain")
}
chainCert, err := exportCertRef(chainCertref)
if err != nil {
return nil, err
}
chain = append(chain, chainCert)
}
i.chain = chain
return chain, nil
}
// Signer implements the Identity interface.
func (i *macIdentity) Signer() (crypto.Signer, error) {
// pre-load the certificate so Public() is less likely to return nil
// unexpectedly.
if _, err := i.Certificate(); err != nil {
return nil, err
}
return i, nil
}
// Delete implements the Identity interface.
func (i *macIdentity) Delete() error {
itemList := []C.SecIdentityRef{i.ref}
itemListPtr := (*unsafe.Pointer)(unsafe.Pointer(&itemList[0]))
citemList := C.CFArrayCreate(nilCFAllocatorRef, itemListPtr, 1, nil)
if citemList == nilCFArrayRef {
return errors.New("error creating CFArray")
}
defer C.CFRelease(C.CFTypeRef(citemList))
query := mapToCFDictionary(map[C.CFTypeRef]C.CFTypeRef{
C.CFTypeRef(C.kSecClass): C.CFTypeRef(C.kSecClassIdentity),
C.CFTypeRef(C.kSecMatchItemList): C.CFTypeRef(citemList),
})
if query == nilCFDictionaryRef {
return errors.New("error creating CFDictionary")
}
defer C.CFRelease(C.CFTypeRef(query))
if err := osStatusError(C.SecItemDelete(query)); err != nil {
return err
}
return nil
}
// Close implements the Identity interface.
func (i *macIdentity) Close() {
if i.ref != nilSecIdentityRef {
C.CFRelease(C.CFTypeRef(i.ref))
i.ref = nilSecIdentityRef
}
if i.kref != nilSecKeyRef {
C.CFRelease(C.CFTypeRef(i.kref))
i.kref = nilSecKeyRef
}
if i.cref != nilSecCertificateRef {
C.CFRelease(C.CFTypeRef(i.cref))
i.cref = nilSecCertificateRef
}
}
// Public implements the crypto.Signer interface.
func (i *macIdentity) Public() crypto.PublicKey {
cert, err := i.Certificate()
if err != nil {
return nil
}
return cert.PublicKey
}
// Sign implements the crypto.Signer interface.
func (i *macIdentity) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
hash := opts.HashFunc()
if len(digest) != hash.Size() {
return nil, errors.New("bad digest for hash")
}
kref, err := i.getKeyRef()
if err != nil {
return nil, err
}
cdigest, err := bytesToCFData(digest)
if err != nil {
return nil, err
}
defer C.CFRelease(C.CFTypeRef(cdigest))
algo, err := i.getAlgo(opts)
if err != nil {
return nil, err
}
// sign the digest
var cerr C.CFErrorRef
csig := C.SecKeyCreateSignature(kref, algo, cdigest, &cerr)
if err := cfErrorError(cerr); err != nil {
defer C.CFRelease(C.CFTypeRef(cerr))
return nil, err
}
if csig == nilCFDataRef {
return nil, errors.New("nil signature from SecKeyCreateSignature")
}
defer C.CFRelease(C.CFTypeRef(csig))
sig := cfDataToBytes(csig)
return sig, nil
}
// getAlgo decides which algorithm to use with this key type for the given hash.
func (i *macIdentity) getAlgo(opts crypto.SignerOpts) (algo C.SecKeyAlgorithm, err error) {
hash := opts.HashFunc()
var crt *x509.Certificate
if crt, err = i.Certificate(); err != nil {
return
}
switch crt.PublicKey.(type) {
case *ecdsa.PublicKey:
switch hash {
case crypto.SHA256:
algo = C.kSecKeyAlgorithmECDSASignatureDigestX962SHA256
case crypto.SHA384:
algo = C.kSecKeyAlgorithmECDSASignatureDigestX962SHA384
case crypto.SHA512:
algo = C.kSecKeyAlgorithmECDSASignatureDigestX962SHA512
default:
err = ErrUnsupportedHash
}
case *rsa.PublicKey:
if _, ok := opts.(*rsa.PSSOptions); ok {
switch hash {
case crypto.SHA256:
algo = C.kSecKeyAlgorithmRSASignatureDigestPSSSHA256
case crypto.SHA384:
algo = C.kSecKeyAlgorithmRSASignatureDigestPSSSHA384
case crypto.SHA512:
algo = C.kSecKeyAlgorithmRSASignatureDigestPSSSHA512
default:
err = ErrUnsupportedHash
}
return
}
switch hash {
case crypto.SHA256:
algo = C.kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256
case crypto.SHA384:
algo = C.kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384
case crypto.SHA512:
algo = C.kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512
default:
err = ErrUnsupportedHash
}
default:
err = errors.New("unsupported key type")
}
return
}
// getKeyRef gets the SecKeyRef for this identity's pricate key.
func (i *macIdentity) getKeyRef() (C.SecKeyRef, error) {
if i.kref != nilSecKeyRef {
return i.kref, nil
}
var keyRef C.SecKeyRef
if err := osStatusError(C.SecIdentityCopyPrivateKey(i.ref, &keyRef)); err != nil {
return nilSecKeyRef, err
}
i.kref = keyRef
return i.kref, nil
}
// getCertRef gets the SecCertificateRef for this identity's certificate.
func (i *macIdentity) getCertRef() (C.SecCertificateRef, error) {
if i.cref != nilSecCertificateRef {
return i.cref, nil
}
var certRef C.SecCertificateRef
if err := osStatusError(C.SecIdentityCopyCertificate(i.ref, &certRef)); err != nil {
return nilSecCertificateRef, err
}
i.cref = certRef
return i.cref, nil
}
// exportCertRef gets a *x509.Certificate for the given SecCertificateRef.
func exportCertRef(certRef C.SecCertificateRef) (*x509.Certificate, error) {
derRef := C.SecCertificateCopyData(certRef)
if derRef == nilCFDataRef {
return nil, errors.New("error getting certificate from identity")
}
defer C.CFRelease(C.CFTypeRef(derRef))
der := cfDataToBytes(derRef)
crt, err := x509.ParseCertificate(der)
if err != nil {
return nil, err
}
return crt, nil
}
// stringToCFString converts a Go string to a CFStringRef.
func stringToCFString(gostr string) C.CFStringRef {
cstr := C.CString(gostr)
defer C.free(unsafe.Pointer(cstr))
return C.CFStringCreateWithCString(nilCFAllocatorRef, cstr, C.kCFStringEncodingUTF8)
}
// mapToCFDictionary converts a Go map[C.CFTypeRef]C.CFTypeRef to a
// CFDictionaryRef.
func mapToCFDictionary(gomap map[C.CFTypeRef]C.CFTypeRef) C.CFDictionaryRef {
var (
n = len(gomap)
keys = make([]unsafe.Pointer, 0, n)
values = make([]unsafe.Pointer, 0, n)
)
for k, v := range gomap {
keys = append(keys, unsafe.Pointer(k))
values = append(values, unsafe.Pointer(v))
}
return C.CFDictionaryCreate(nilCFAllocatorRef, &keys[0], &values[0], C.CFIndex(n), nil, nil)
}
// cfDataToBytes converts a CFDataRef to a Go byte slice.
func cfDataToBytes(cfdata C.CFDataRef) []byte {
nBytes := C.CFDataGetLength(cfdata)
bytesPtr := C.CFDataGetBytePtr(cfdata)
return C.GoBytes(unsafe.Pointer(bytesPtr), C.int(nBytes))
}
// bytesToCFData converts a Go byte slice to a CFDataRef.
func bytesToCFData(gobytes []byte) (C.CFDataRef, error) {
var (
cptr = (*C.UInt8)(nil)
clen = C.CFIndex(len(gobytes))
)
if len(gobytes) > 0 {
cptr = (*C.UInt8)(&gobytes[0])
}
cdata := C.CFDataCreate(nilCFAllocatorRef, cptr, clen)
if cdata == nilCFDataRef {
return nilCFDataRef, errors.New("error creatin cfdata")
}
return cdata, nil
}
// osStatus wraps a C.OSStatus
type osStatus C.OSStatus
const (
errSecItemNotFound = osStatus(C.errSecItemNotFound)
)
// osStatusError returns an error for an OSStatus unless it is errSecSuccess.
func osStatusError(s C.OSStatus) error {
if s == C.errSecSuccess {
return nil
}
return osStatus(s)
}
// Error implements the error interface.
func (s osStatus) Error() string {
return fmt.Sprintf("OSStatus %d", s)
}
// cfErrorError returns an error for a CFErrorRef unless it is nil.
func cfErrorError(cerr C.CFErrorRef) error {
if cerr == nilCFErrorRef {
return nil
}
code := int(C.CFErrorGetCode(cerr))
if cdescription := C.CFErrorCopyDescription(cerr); cdescription != nilCFStringRef {
defer C.CFRelease(C.CFTypeRef(cdescription))
if cstr := C.CFStringGetCStringPtr(cdescription, C.kCFStringEncodingUTF8); cstr != nil {
str := C.GoString(cstr)
return fmt.Errorf("CFError %d (%s)", code, str)
}
}
return fmt.Errorf("CFError %d", code)
}

View File

@@ -0,0 +1,14 @@
package certstore
import "errors"
// This will hopefully give a compiler error that will hint at the fact that
// this package isn't designed to work on Linux.
func init() {
CERTSTORE_DOESNT_WORK_ON_LINIX
}
// Implement this function, just to silence other compiler errors.
func openStore(location StoreLocation, permissions ...StorePermission) (Store, error) {
return nil, errors.New("certstore only works on macOS and Windows")
}

View File

@@ -0,0 +1,639 @@
package certstore
import (
"crypto"
"crypto/ecdsa"
"crypto/rsa"
"crypto/x509"
"encoding/asn1"
"encoding/binary"
"errors"
"fmt"
"io"
"math/big"
"syscall"
"unsafe"
"golang.org/x/sys/cpu"
"golang.org/x/sys/windows"
)
const myStoreName = "MY"
var (
// winAPIFlag specifies the flags that should be passed to
// CryptAcquireCertificatePrivateKey. This impacts whether the CryptoAPI or CNG
// API will be used.
//
// Possible values are:
//
// 0 — Only use CryptoAPI.
// windows.CRYPT_ACQUIRE_ALLOW_NCRYPT_KEY_FLAG — Prefer CryptoAPI.
// windows.CRYPT_ACQUIRE_PREFER_NCRYPT_KEY_FLAG — Prefer CNG.
// windows.CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG — Only use CNG.
winAPIFlag uint32 = windows.CRYPT_ACQUIRE_PREFER_NCRYPT_KEY_FLAG
)
// winStore is a wrapper around a certStoreHandle.
type winStore struct {
store certStoreHandle
}
// openStore opens the current user's personal cert store.
func openStore(location StoreLocation, permissions ...StorePermission) (*winStore, error) {
storeName, err := windows.UTF16PtrFromString(myStoreName)
if err != nil {
return nil, err
}
var flags uint32
switch location {
case User:
flags |= windows.CERT_SYSTEM_STORE_CURRENT_USER
case System:
flags |= windows.CERT_SYSTEM_STORE_LOCAL_MACHINE
}
for _, p := range permissions {
switch p {
case ReadOnly:
flags |= windows.CERT_STORE_READONLY_FLAG
}
}
store, err := windows.CertOpenStore(windows.CERT_STORE_PROV_SYSTEM_W, 0, 0, flags, uintptr(unsafe.Pointer(storeName)))
if err != nil {
return nil, fmt.Errorf("failed to open system cert store: %w", err)
}
return &winStore{certStoreHandle(store)}, nil
}
// Identities implements the Store interface.
func (s *winStore) Identities() ([]Identity, error) {
var (
err error
idents []Identity
// CertFindChainInStore parameters
encoding = uint32(windows.X509_ASN_ENCODING)
flags = uint32(windows.CERT_CHAIN_FIND_BY_ISSUER_CACHE_ONLY_FLAG | windows.CERT_CHAIN_FIND_BY_ISSUER_CACHE_ONLY_URL_FLAG)
findType = uint32(windows.CERT_CHAIN_FIND_BY_ISSUER)
params = &windows.CertChainFindByIssuerPara{Size: uint32(unsafe.Sizeof(windows.CertChainFindByIssuerPara{}))}
chainCtx *windows.CertChainContext
)
for {
chainCtx, err = windows.CertFindChainInStore(windows.Handle(s.store), encoding, flags, findType, unsafe.Pointer(params), chainCtx)
if errors.Is(err, syscall.Errno(windows.CRYPT_E_NOT_FOUND)) {
return idents, nil
}
if err != nil {
err = fmt.Errorf("failed to iterate certs in store: %w", err)
break
}
if chainCtx.ChainCount < 1 {
err = errors.New("bad chain")
break
}
// not sure why this isn't 1 << 29
const maxPointerArray = 1 << 28
// rgpChain is actually an array, but we only care about the first one.
simpleChain := *chainCtx.Chains
if simpleChain.NumElements < 1 || simpleChain.NumElements > maxPointerArray {
err = errors.New("bad chain")
break
}
chainElts := unsafe.Slice(simpleChain.Elements, simpleChain.NumElements)
// Build chain of certificates from each elt's certificate context.
chain := make([]*windows.CertContext, len(chainElts))
for j := range chainElts {
chain[j] = chainElts[j].CertContext
}
idents = append(idents, newWinIdentity(chain))
}
for _, ident := range idents {
ident.Close()
}
return nil, err
}
// Import implements the Store interface.
func (s *winStore) Import(data []byte, password string) error {
cpw, err := windows.UTF16PtrFromString(password)
if err != nil {
return fmt.Errorf("converting password: %w", err)
}
pfx := &windows.CryptDataBlob{
Size: uint32(len(data)),
Data: unsafe.SliceData(data),
}
var flags uint32
flags = windows.CRYPT_USER_KEYSET
// import into preferred KSP
if winAPIFlag&windows.CRYPT_ACQUIRE_PREFER_NCRYPT_KEY_FLAG > 0 {
flags |= windows.PKCS12_PREFER_CNG_KSP
} else if winAPIFlag&windows.CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG > 0 {
flags |= windows.PKCS12_ALWAYS_CNG_KSP
}
store, err := windows.PFXImportCertStore(pfx, cpw, flags)
if err != nil {
return fmt.Errorf("failed to import PFX cert store: %w", err)
}
defer windows.CertCloseStore(store, windows.CERT_CLOSE_STORE_FORCE_FLAG)
var (
ctx *windows.CertContext
encoding = uint32(windows.X509_ASN_ENCODING | windows.PKCS_7_ASN_ENCODING)
)
for {
// iterate through certs in temporary store
ctx, err = windows.CertFindCertificateInStore(store, encoding, 0, windows.CERT_FIND_ANY, nil, ctx)
if errors.Is(err, syscall.Errno(windows.CRYPT_E_NOT_FOUND)) {
break
}
if err != nil {
return fmt.Errorf("failed to iterate certs in store: %w", err)
}
// Copy the cert to the system store.
if err := windows.CertAddCertificateContextToStore(windows.Handle(s.store), ctx, windows.CERT_STORE_ADD_REPLACE_EXISTING, nil); err != nil {
return fmt.Errorf("failed to add imported certificate to %s store: %w", myStoreName, err)
}
}
return nil
}
// Close implements the Store interface.
func (s *winStore) Close() {
windows.CertCloseStore(windows.Handle(s.store), 0)
s.store = 0
}
// winIdentity implements the Identity interface.
type winIdentity struct {
chain []*windows.CertContext
signer *winPrivateKey
}
func newWinIdentity(chain []*windows.CertContext) *winIdentity {
for _, ctx := range chain {
windows.CertDuplicateCertificateContext(ctx)
}
return &winIdentity{chain: chain}
}
// Certificate implements the Identity interface.
func (i *winIdentity) Certificate() (*x509.Certificate, error) {
return exportCertCtx(i.chain[0])
}
// CertificateChain implements the Identity interface.
func (i *winIdentity) CertificateChain() ([]*x509.Certificate, error) {
var (
certs = make([]*x509.Certificate, len(i.chain))
err error
)
for j := range i.chain {
if certs[j], err = exportCertCtx(i.chain[j]); err != nil {
return nil, err
}
}
return certs, nil
}
// Signer implements the Identity interface.
func (i *winIdentity) Signer() (crypto.Signer, error) {
return i.getPrivateKey()
}
// getPrivateKey gets this identity's private *winPrivateKey.
func (i *winIdentity) getPrivateKey() (*winPrivateKey, error) {
if i.signer != nil {
return i.signer, nil
}
cert, err := i.Certificate()
if err != nil {
return nil, fmt.Errorf("failed to get identity certificate: %w", err)
}
signer, err := newWinPrivateKey(i.chain[0], cert.PublicKey)
if err != nil {
return nil, fmt.Errorf("failed to load identity private key: %w", err)
}
i.signer = signer
return i.signer, nil
}
// Delete implements the Identity interface.
func (i *winIdentity) Delete() error {
// duplicate cert context, since CertDeleteCertificateFromStore will free it.
deleteCtx := windows.CertDuplicateCertificateContext(i.chain[0])
// try deleting cert
if err := windows.CertDeleteCertificateFromStore(deleteCtx); err != nil {
return fmt.Errorf("failed to delete certificate from store: %w", err)
}
// try deleting private key
wpk, err := i.getPrivateKey()
if err != nil {
return fmt.Errorf("failed to get identity private key: %w", err)
}
if err := wpk.Delete(); err != nil {
return fmt.Errorf("failed to delete identity private key: %w", err)
}
return nil
}
// Close implements the Identity interface.
func (i *winIdentity) Close() {
if i.signer != nil {
i.signer.Close()
i.signer = nil
}
for _, ctx := range i.chain {
_ = windows.CertFreeCertificateContext(ctx)
i.chain = nil
}
}
// winPrivateKey is a wrapper around a HCRYPTPROV_OR_NCRYPT_KEY_HANDLE.
type winPrivateKey struct {
publicKey crypto.PublicKey
// CryptoAPI fields
capiProv cryptProviderHandle
// CNG fields
cngHandle nCryptKeyHandle
keySpec uint32
}
// newWinPrivateKey gets a *winPrivateKey for the given certificate.
func newWinPrivateKey(certCtx *windows.CertContext, publicKey crypto.PublicKey) (*winPrivateKey, error) {
var (
provOrKey windows.Handle // HCRYPTPROV_OR_NCRYPT_KEY_HANDLE
keySpec uint32
mustFree bool
)
if publicKey == nil {
return nil, errors.New("nil public key")
}
// Get a handle for the found private key.
if err := windows.CryptAcquireCertificatePrivateKey(certCtx, winAPIFlag, nil, &provOrKey, &keySpec, &mustFree); err != nil {
return nil, fmt.Errorf("failed to get private key for certificate: %w", err)
}
if !mustFree {
// This shouldn't happen since we're not asking for cached keys.
return nil, errors.New("CryptAcquireCertificatePrivateKey set mustFree")
}
if keySpec == windows.CERT_NCRYPT_KEY_SPEC {
return &winPrivateKey{
publicKey: publicKey,
cngHandle: nCryptKeyHandle(provOrKey),
}, nil
} else {
return &winPrivateKey{
publicKey: publicKey,
capiProv: cryptProviderHandle(provOrKey),
keySpec: keySpec,
}, nil
}
}
// Public implements the crypto.Signer interface.
func (wpk *winPrivateKey) Public() crypto.PublicKey {
return wpk.publicKey
}
// Sign implements the crypto.Signer interface.
func (wpk *winPrivateKey) Sign(_ io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
if wpk.capiProv != 0 {
return wpk.capiSignHash(opts, digest)
} else if wpk.cngHandle != 0 {
return wpk.cngSignHash(opts, digest)
} else {
return nil, errors.New("bad private key")
}
}
type bCryptPKCS1PaddingInfo struct {
// Algorithm is the name of the hashing algorithm to use, in UTF16. Use one
// of the BCRYPT_*_ALGORITHM constants.
Algorithm *uint16
}
type bCryptPSSPaddingInfo struct {
// Algorithm is the name of the hashing algorithm to use, in UTF16. Use one
// of the BCRYPT_*_ALGORITHM constants.
Algorithm *uint16
// SaltLength is the size, in bytes, of the random salt to use for the
// padding.
SaltLength uint32
}
// cngSignHash signs a digest using the CNG APIs.
func (wpk *winPrivateKey) cngSignHash(opts crypto.SignerOpts, digest []byte) ([]byte, error) {
hash := opts.HashFunc()
if len(digest) != hash.Size() {
return nil, errors.New("cngSignHash: bad digest for hash")
}
var (
// input
padPtr unsafe.Pointer
digestPtr = unsafe.SliceData(digest)
digestLen = uint32(len(digest))
flags uint32
// output
sigLen uint32
)
// setup pkcs1v1.5 padding for RSA
if _, isRSA := wpk.publicKey.(*rsa.PublicKey); isRSA {
var alg string
switch hash {
case crypto.SHA256:
alg = BCRYPT_SHA256_ALGORITHM
case crypto.SHA384:
alg = BCRYPT_SHA384_ALGORITHM
case crypto.SHA512:
alg = BCRYPT_SHA512_ALGORITHM
default:
return nil, fmt.Errorf("cngSignHash: converting from Go algorithm: %w", ErrUnsupportedHash)
}
algName, err := windows.UTF16PtrFromString(alg)
if err != nil {
return nil, err
}
if pssOpts, ok := opts.(*rsa.PSSOptions); ok {
saltLen := pssOpts.SaltLength
if saltLen == rsa.PSSSaltLengthEqualsHash {
saltLen = len(digest)
} else if saltLen == rsa.PSSSaltLengthAuto {
saltLen = hash.Size()
}
padPtr = unsafe.Pointer(&bCryptPSSPaddingInfo{
Algorithm: algName,
SaltLength: uint32(saltLen),
})
flags |= BCRYPT_PAD_PSS
} else {
padPtr = unsafe.Pointer(&bCryptPKCS1PaddingInfo{
Algorithm: algName,
})
flags |= BCRYPT_PAD_PKCS1
}
}
// get signature length
if err := nCryptSignHash(wpk.cngHandle, padPtr, digestPtr, digestLen, nil, 0, &sigLen, flags); err != nil {
return nil, fmt.Errorf("cngSignHash: failed to get signature length: %w", err)
}
// get signature
sig := make([]byte, sigLen)
if err := nCryptSignHash(wpk.cngHandle, padPtr, digestPtr, digestLen, unsafe.SliceData(sig), sigLen, &sigLen, flags); err != nil {
return nil, fmt.Errorf("cngSignHash: failed to sign digest: %w", err)
}
// CNG returns a raw ECDSA signature, but we wan't ASN.1 DER encoding.
if _, isEC := wpk.publicKey.(*ecdsa.PublicKey); isEC {
if len(sig)%2 != 0 {
return nil, errors.New("cngSignHash: bad ecdsa signature from CNG")
}
type ecdsaSignature struct {
R, S *big.Int
}
r := new(big.Int).SetBytes(sig[:len(sig)/2])
s := new(big.Int).SetBytes(sig[len(sig)/2:])
encoded, err := asn1.Marshal(ecdsaSignature{r, s})
if err != nil {
return nil, fmt.Errorf("cngSignHash: failed to ASN.1 encode EC signature: %w", err)
}
return encoded, nil
}
return sig, nil
}
// capiSignHash signs a digest using the CryptoAPI APIs.
func (wpk *winPrivateKey) capiSignHash(opts crypto.SignerOpts, digest []byte) ([]byte, error) {
if _, ok := opts.(*rsa.PSSOptions); ok {
return nil, fmt.Errorf("capiSignHash: CAPI does not support PSS padding, %w", ErrUnsupportedHash)
}
hash := opts.HashFunc()
if len(digest) != hash.Size() {
return nil, errors.New("capiSignHash: bad digest for hash")
}
// Figure out which CryptoAPI hash algorithm we're using.
var hash_alg cryptAlgorithm
switch hash {
case crypto.SHA256:
hash_alg = CALG_SHA_256
case crypto.SHA384:
hash_alg = CALG_SHA_384
case crypto.SHA512:
hash_alg = CALG_SHA_512
default:
return nil, fmt.Errorf("capiSignHash: converting from Go algorithm: %w", ErrUnsupportedHash)
}
// Instantiate a CryptoAPI hash object.
var chash cryptHashHandle
if err := cryptCreateHash(wpk.capiProv, hash_alg, 0, 0, &chash); err != nil {
if errors.Is(err, syscall.Errno(windows.NTE_BAD_ALGID)) {
err = ErrUnsupportedHash
}
return nil, fmt.Errorf("capiSignHash: cryptCreateHash: %w", err)
}
defer cryptDestroyHash(chash)
// Make sure the hash size matches.
var (
hashSize uint32
hashSizeLen = uint32(unsafe.Sizeof(hashSize))
)
if err := cryptGetHashParam(chash, HP_HASHSIZE, unsafe.Pointer(&hashSize), &hashSizeLen, 0); err != nil {
return nil, fmt.Errorf("capiSignHash: failed to get hash size: %w", err)
}
if hash.Size() != int(hashSize) {
return nil, errors.New("capiSignHash: invalid CryptoAPI hash")
}
// Put our digest into the hash object.
if err := cryptSetHashParam(chash, HP_HASHVAL, unsafe.Pointer(unsafe.SliceData(digest)), 0); err != nil {
return nil, fmt.Errorf("capiSignHash: failed to set hash digest: %w", err)
}
// Get signature length.
var sigLen uint32
if err := cryptSignHash(chash, wpk.keySpec, nil, 0, nil, &sigLen); err != nil {
return nil, fmt.Errorf("capiSignHash: failed to get signature length: %w", err)
}
// Get signature
sig := make([]byte, int(sigLen))
if err := cryptSignHash(chash, wpk.keySpec, nil, 0, unsafe.SliceData(sig), &sigLen); err != nil {
return nil, fmt.Errorf("capiSignHash: failed to sign digest: %w", err)
}
// Signature is little endian, but we want big endian. Reverse it.
for i := len(sig)/2 - 1; i >= 0; i-- {
opp := len(sig) - 1 - i
sig[i], sig[opp] = sig[opp], sig[i]
}
return sig, nil
}
func (wpk *winPrivateKey) Delete() error {
if wpk.cngHandle != 0 {
// Delete CNG key
if err := nCryptDeleteKey(wpk.cngHandle, 0); err != nil {
return err
}
} else if wpk.capiProv != 0 {
// Delete CryptoAPI key
var (
containerName string
providerName string
providerType uint32
err error
)
containerName, err = wpk.getProviderStringParam(PP_CONTAINER)
if err != nil {
return fmt.Errorf("failed to get PP_CONTAINER: %w", err)
}
providerName, err = wpk.getProviderStringParam(PP_NAME)
if err != nil {
return fmt.Errorf("failed to get PP_NAME: %w", err)
}
providerType, err = wpk.getProviderUint32Param(PP_PROVTYPE)
if err != nil {
return fmt.Errorf("failed to get PP_PROVTYPE: %w", err)
}
// use CRYPT_SILENT too?
var prov windows.Handle
if err := windows.CryptAcquireContext(&prov, windows.StringToUTF16Ptr(containerName), windows.StringToUTF16Ptr(providerName),
providerType, windows.CRYPT_DELETEKEYSET); err != nil {
return fmt.Errorf("failed to delete key set (container=%q, name=%q, provtype=%d): %w",
containerName, providerName, providerType, err)
}
wpk.capiProv = 0
} else {
return errors.New("bad private key")
}
return nil
}
// getProviderParam gets a parameter about a provider.
func (wpk *winPrivateKey) getProviderParam(param uint32) ([]byte, error) {
var dataLen uint32
if err := cryptGetProvParam(wpk.capiProv, param, nil, &dataLen, 0); err != nil {
return nil, fmt.Errorf("failed to get provider parameter size: %w", err)
}
data := make([]byte, dataLen)
if err := cryptGetProvParam(wpk.capiProv, param, unsafe.SliceData(data), &dataLen, 0); err != nil {
return nil, fmt.Errorf("failed to get provider parameter: %w", err)
}
return data, nil
}
// getProviderStringParam gets a parameter about a provider. The parameter is a zero-terminated char string.
func (wpk *winPrivateKey) getProviderStringParam(param uint32) (string, error) {
val, err := wpk.getProviderParam(param)
if err != nil {
return "", err
}
return windows.ByteSliceToString(val), nil
}
// getProviderUint32Param gets a parameter about a provider. The parameter is a uint32.
func (wpk *winPrivateKey) getProviderUint32Param(param uint32) (uint32, error) {
val, err := wpk.getProviderParam(param)
if err != nil {
return 0, err
}
if len(val) != 4 {
return 0, errors.New("uint32 data length is not 32 bits")
}
if cpu.IsBigEndian {
return binary.BigEndian.Uint32(val), nil
}
return binary.LittleEndian.Uint32(val), nil
}
// Close closes this winPrivateKey.
func (wpk *winPrivateKey) Close() {
if wpk.cngHandle != 0 {
_ = nCryptFreeObject(windows.Handle(wpk.cngHandle))
wpk.cngHandle = 0
}
if wpk.capiProv != 0 {
_ = windows.CryptReleaseContext(windows.Handle(wpk.capiProv), 0)
wpk.capiProv = 0
}
}
// exportCertCtx exports a *windows.CertContext as an *x509.Certificate.
func exportCertCtx(ctx *windows.CertContext) (*x509.Certificate, error) {
der := unsafe.Slice(ctx.EncodedCert, ctx.Length)
cert, err := x509.ParseCertificate(der)
if err != nil {
return nil, fmt.Errorf("certificate parsing failed: %w", err)
}
return cert, nil
}

View File

@@ -0,0 +1,79 @@
package certstore
const (
// NCRYPT Object Property Names
NCRYPT_ALGORITHM_GROUP_PROPERTY = "Algorithm Group"
NCRYPT_ALGORITHM_PROPERTY = "Algorithm Name"
NCRYPT_BLOCK_LENGTH_PROPERTY = "Block Length"
NCRYPT_CERTIFICATE_PROPERTY = "SmartCardKeyCertificate"
NCRYPT_DH_PARAMETERS_PROPERTY = BCRYPT_DH_PARAMETERS
BCRYPT_DH_PARAMETERS = "DHParameters"
NCRYPT_EXPORT_POLICY_PROPERTY = "Export Policy"
NCRYPT_IMPL_TYPE_PROPERTY = "Impl Type"
NCRYPT_KEY_TYPE_PROPERTY = "Key Type"
NCRYPT_KEY_USAGE_PROPERTY = "Key Usage"
NCRYPT_LAST_MODIFIED_PROPERTY = "Modified"
NCRYPT_LENGTH_PROPERTY = "Length"
NCRYPT_LENGTHS_PROPERTY = "Lengths"
NCRYPT_MAX_NAME_LENGTH_PROPERTY = "Max Name Length"
NCRYPT_NAME_PROPERTY = "Name"
NCRYPT_PIN_PROMPT_PROPERTY = "SmartCardPinPrompt"
NCRYPT_PIN_PROPERTY = "SmartCardPin"
NCRYPT_PROVIDER_HANDLE_PROPERTY = "Provider Handle"
NCRYPT_READER_PROPERTY = "SmartCardReader"
NCRYPT_ROOT_CERTSTORE_PROPERTY = "SmartcardRootCertStore"
NCRYPT_SECURE_PIN_PROPERTY = "SmartCardSecurePin"
NCRYPT_SECURITY_DESCR_PROPERTY = "Security Descr"
NCRYPT_SECURITY_DESCR_SUPPORT_PROPERTY = "Security Descr Support"
NCRYPT_SMARTCARD_GUID_PROPERTY = "SmartCardGuid"
NCRYPT_UI_POLICY_PROPERTY = "UI Policy"
NCRYPT_UNIQUE_NAME_PROPERTY = "Unique Name"
NCRYPT_USE_CONTEXT_PROPERTY = "Use Context"
NCRYPT_USE_COUNT_ENABLED_PROPERTY = "Enabled Use Count"
NCRYPT_USE_COUNT_PROPERTY = "Use Count"
NCRYPT_USER_CERTSTORE_PROPERTY = "SmartCardUserCertStore"
NCRYPT_VERSION_PROPERTY = "Version"
NCRYPT_WINDOW_HANDLE_PROPERTY = "HWND Handle"
// BCRYPT BLOB Types
BCRYPT_DH_PRIVATE_BLOB = "DHPRIVATEBLOB"
BCRYPT_DH_PUBLIC_BLOB = "DHPUBLICBLOB"
BCRYPT_DSA_PRIVATE_BLOB = "DSAPRIVATEBLOB"
BCRYPT_DSA_PUBLIC_BLOB = "DSAPUBLICBLOB"
BCRYPT_ECCPRIVATE_BLOB = "ECCPRIVATEBLOB"
BCRYPT_ECCPUBLIC_BLOB = "ECCPUBLICBLOB"
BCRYPT_PRIVATE_KEY_BLOB = "PRIVATEBLOB"
BCRYPT_PUBLIC_KEY_BLOB = "PUBLICBLOB"
BCRYPT_RSAFULLPRIVATE_BLOB = "RSAFULLPRIVATEBLOB"
BCRYPT_RSAPRIVATE_BLOB = "RSAPRIVATEBLOB"
BCRYPT_RSAPUBLIC_BLOB = "RSAPUBLICBLOB"
// BCRYPT Algorithm Names
BCRYPT_3DES_ALGORITHM = "3DES"
BCRYPT_AES_ALGORITHM = "AES"
BCRYPT_DES_ALGORITHM = "DES"
BCRYPT_DSA_ALGORITHM = "DSA"
BCRYPT_ECDH_P256_ALGORITHM = "ECDH_P256"
BCRYPT_ECDH_P384_ALGORITHM = "ECDH_P384"
BCRYPT_ECDSA_P256_ALGORITHM = "ECDSA_P256"
BCRYPT_ECDSA_P384_ALGORITHM = "ECDSA_P384"
BCRYPT_ECDSA_P521_ALGORITHM = "ECDSA_P521"
BCRYPT_MD2_ALGORITHM = "MD2"
BCRYPT_MD4_ALGORITHM = "MD4"
BCRYPT_MD5_ALGORITHM = "MD5"
BCRYPT_RC2_ALGORITHM = "RC2"
BCRYPT_RC4_ALGORITHM = "RC4"
BCRYPT_RNG_ALGORITHM = "RNG"
BCRYPT_RSA_ALGORITHM = "RSA"
BCRYPT_RSA_SIGN_ALGORITHM = "RSA_SIGN"
BCRYPT_SHA1_ALGORITHM = "SHA1"
BCRYPT_SHA256_ALGORITHM = "SHA256"
BCRYPT_SHA384_ALGORITHM = "SHA384"
BCRYPT_SHA512_ALGORITHM = "SHA512"
BCRYPT_SP800108_CTR_HMAC_ALGORITHM = "SP800_108_CTR_HMAC"
BCRYPT_SP80056A_CONCAT_ALGORITHM = "SP800_56A_CONCAT"
BCRYPT_PBKDF2_ALGORITHM = "PBKDF2"
BCRYPT_ECDSA_ALGORITHM = "ECDSA"
BCRYPT_ECDH_ALGORITHM = "ECDH"
BCRYPT_XTS_AES_ALGORITHM = "XTS-AES"
)

View File

@@ -0,0 +1,67 @@
package certstore
import (
"golang.org/x/sys/windows"
)
//go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go syscall_windows.go
type certStoreHandle windows.Handle
// CryptoAPI APIs from wincrypt.h
type cryptProviderHandle windows.Handle // HCRYPTPROV
type cryptHashHandle windows.Handle // HCRYPTHASH
type cryptKeyHandle windows.Handle // HCRYPTKEY
type cryptAlgorithm uint32 // ALG_ID
const (
// Values for ALG_ID
CALG_SHA_256 cryptAlgorithm = 0x0000800c
CALG_SHA_384 cryptAlgorithm = 0x0000800d
CALG_SHA_512 cryptAlgorithm = 0x0000800e
// Values of the dwParam for CryptGetHashParam and/or CryptSetHashParam
HP_ALGID = 0x1
HP_HASHVAL = 0x2
HP_HASHSIZE = 0x4
HP_HMAC_INFO = 0x5
// Values of the dwParam for CryptGetProvParam and/or CryptSetProvParam
PP_NAME = 4
PP_CONTAINER = 6
PP_PROVTYPE = 16
)
// https://learn.microsoft.com/en-ca/windows/win32/api/wincrypt/nf-wincrypt-cryptcreatehash
//sys cryptCreateHash(hProv cryptProviderHandle, Algid cryptAlgorithm, hKey cryptKeyHandle, dwFlags uint32, phHash *cryptHashHandle) (err error) = advapi32.CryptCreateHash
// https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptdestroyhash
//sys cryptDestroyHash(hHash cryptHashHandle) (err error) = advapi32.CryptDestroyHash
// https://learn.microsoft.com/en-ca/windows/win32/api/wincrypt/nf-wincrypt-cryptgethashparam
//sys cryptGetHashParam(hHash cryptHashHandle, dwParam uint32, pbData unsafe.Pointer, pdwDataLen *uint32, dwFlags uint32) (err error) = advapi32.CryptGetHashParam
// https://learn.microsoft.com/en-ca/windows/win32/api/wincrypt/nf-wincrypt-cryptsethashparam
//sys cryptSetHashParam(hHash cryptHashHandle, dwParam uint32, pbData unsafe.Pointer, dwFlags uint32) (err error) = advapi32.CryptSetHashParam
// https://learn.microsoft.com/en-ca/windows/win32/api/wincrypt/nf-wincrypt-cryptsignhashw
//sys cryptSignHash(hHash cryptHashHandle, dwKeySpec uint32, szDescription *uint16, dwFlags uint32, pbSignature *byte, pdwSigLen *uint32) (err error) = advapi32.CryptSignHashW
// https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptgetprovparam
//sys cryptGetProvParam(hProv cryptProviderHandle, dwParam uint32, pbData *byte, pdwDataLen *uint32, dwFlags uint32) (err error) = advapi32.CryptGetProvParam
// https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptsetprovparam
//sys cryptSetProvParam(hProv cryptProviderHandle, dwParam uint32, pbData *byte, dwFlags uint32) (err error) = advapi32.CryptSetProvParam
// CNG APIs from bcrypt.h and ncrypt.h.
const (
// Flags for NCryptSignHash and others
BCRYPT_PAD_NONE = 0x00000001
BCRYPT_PAD_PKCS1 = 0x00000002
BCRYPT_PAD_OAEP = 0x00000004
BCRYPT_PAD_PSS = 0x00000008
)
type nCryptKeyHandle windows.Handle
// https://learn.microsoft.com/en-us/windows/win32/api/ncrypt/nf-ncrypt-ncryptsignhash
//sys nCryptSignHash(hKey nCryptKeyHandle, pPaddingInfo unsafe.Pointer, pbHashValue *byte, cbHashValue uint32, pbSignature *byte, cbSignature uint32, pcbResult *uint32, dwFlags uint32) (ret error) = ncrypt.NCryptSignHash
// https://learn.microsoft.com/en-us/windows/win32/api/ncrypt/nf-ncrypt-ncryptdeletekey
//sys nCryptDeleteKey(hKey nCryptKeyHandle, dwFlags uint32) (ret error) = ncrypt.NCryptDeleteKey
// https://learn.microsoft.com/en-us/windows/win32/api/ncrypt/nf-ncrypt-ncryptfreeobject
//sys nCryptFreeObject(hObject windows.Handle) (ret error) = ncrypt.NCryptFreeObject

View File

@@ -0,0 +1,134 @@
// Code generated by 'go generate'; DO NOT EDIT.
package certstore
import (
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
var _ unsafe.Pointer
// Do the interface allocations only once for common
// Errno values.
const (
errnoERROR_IO_PENDING = 997
)
var (
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
errERROR_EINVAL error = syscall.EINVAL
)
// errnoErr returns common boxed Errno values, to prevent
// allocations at runtime.
func errnoErr(e syscall.Errno) error {
switch e {
case 0:
return errERROR_EINVAL
case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING
}
// TODO: add more here, after collecting data on the common
// error values see on Windows. (perhaps when running
// all.bat?)
return e
}
var (
modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
modncrypt = windows.NewLazySystemDLL("ncrypt.dll")
procCryptCreateHash = modadvapi32.NewProc("CryptCreateHash")
procCryptDestroyHash = modadvapi32.NewProc("CryptDestroyHash")
procCryptGetHashParam = modadvapi32.NewProc("CryptGetHashParam")
procCryptGetProvParam = modadvapi32.NewProc("CryptGetProvParam")
procCryptSetHashParam = modadvapi32.NewProc("CryptSetHashParam")
procCryptSetProvParam = modadvapi32.NewProc("CryptSetProvParam")
procCryptSignHashW = modadvapi32.NewProc("CryptSignHashW")
procNCryptDeleteKey = modncrypt.NewProc("NCryptDeleteKey")
procNCryptFreeObject = modncrypt.NewProc("NCryptFreeObject")
procNCryptSignHash = modncrypt.NewProc("NCryptSignHash")
)
func cryptCreateHash(hProv cryptProviderHandle, Algid cryptAlgorithm, hKey cryptKeyHandle, dwFlags uint32, phHash *cryptHashHandle) (err error) {
r1, _, e1 := syscall.Syscall6(procCryptCreateHash.Addr(), 5, uintptr(hProv), uintptr(Algid), uintptr(hKey), uintptr(dwFlags), uintptr(unsafe.Pointer(phHash)), 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func cryptDestroyHash(hHash cryptHashHandle) (err error) {
r1, _, e1 := syscall.Syscall(procCryptDestroyHash.Addr(), 1, uintptr(hHash), 0, 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func cryptGetHashParam(hHash cryptHashHandle, dwParam uint32, pbData unsafe.Pointer, pdwDataLen *uint32, dwFlags uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procCryptGetHashParam.Addr(), 5, uintptr(hHash), uintptr(dwParam), uintptr(pbData), uintptr(unsafe.Pointer(pdwDataLen)), uintptr(dwFlags), 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func cryptGetProvParam(hProv cryptProviderHandle, dwParam uint32, pbData *byte, pdwDataLen *uint32, dwFlags uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procCryptGetProvParam.Addr(), 5, uintptr(hProv), uintptr(dwParam), uintptr(unsafe.Pointer(pbData)), uintptr(unsafe.Pointer(pdwDataLen)), uintptr(dwFlags), 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func cryptSetHashParam(hHash cryptHashHandle, dwParam uint32, pbData unsafe.Pointer, dwFlags uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procCryptSetHashParam.Addr(), 4, uintptr(hHash), uintptr(dwParam), uintptr(pbData), uintptr(dwFlags), 0, 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func cryptSetProvParam(hProv cryptProviderHandle, dwParam uint32, pbData *byte, dwFlags uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procCryptSetProvParam.Addr(), 4, uintptr(hProv), uintptr(dwParam), uintptr(unsafe.Pointer(pbData)), uintptr(dwFlags), 0, 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func cryptSignHash(hHash cryptHashHandle, dwKeySpec uint32, szDescription *uint16, dwFlags uint32, pbSignature *byte, pdwSigLen *uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procCryptSignHashW.Addr(), 6, uintptr(hHash), uintptr(dwKeySpec), uintptr(unsafe.Pointer(szDescription)), uintptr(dwFlags), uintptr(unsafe.Pointer(pbSignature)), uintptr(unsafe.Pointer(pdwSigLen)))
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func nCryptDeleteKey(hKey nCryptKeyHandle, dwFlags uint32) (ret error) {
r0, _, _ := syscall.Syscall(procNCryptDeleteKey.Addr(), 2, uintptr(hKey), uintptr(dwFlags), 0)
if r0 != 0 {
ret = syscall.Errno(r0)
}
return
}
func nCryptFreeObject(hObject windows.Handle) (ret error) {
r0, _, _ := syscall.Syscall(procNCryptFreeObject.Addr(), 1, uintptr(hObject), 0, 0)
if r0 != 0 {
ret = syscall.Errno(r0)
}
return
}
func nCryptSignHash(hKey nCryptKeyHandle, pPaddingInfo unsafe.Pointer, pbHashValue *byte, cbHashValue uint32, pbSignature *byte, cbSignature uint32, pcbResult *uint32, dwFlags uint32) (ret error) {
r0, _, _ := syscall.Syscall9(procNCryptSignHash.Addr(), 8, uintptr(hKey), uintptr(pPaddingInfo), uintptr(unsafe.Pointer(pbHashValue)), uintptr(cbHashValue), uintptr(unsafe.Pointer(pbSignature)), uintptr(cbSignature), uintptr(unsafe.Pointer(pcbResult)), uintptr(dwFlags), 0)
if r0 != 0 {
ret = syscall.Errno(r0)
}
return
}