1

My project is to create a script in Golang that signs a document with a PIV card digital signature and then allows you to verify the signature with the piv card's certificate. I've got the first part working. What I'm running into is getting the verification working. I'm trying to import the public key from the certificate using the Windows CNG apis and I can't get it to work. I pulled that specific part of the code out to try and get that working. I've included the snippet below. When I run it, I get this error:

CryptDecodeObjectEx failed: The system cannot find the file specified.

Note: this pops up after it's retrieved the cert.pem file and parsed it.

I used this to create a pem cert to test this with:

openssl req -x509 -newkey rsa:2048 -nodes -keyout key.pem -out cert.pem

package main
import (
 "encoding/pem"
 "fmt"
 "os"
 "syscall"
 "unsafe"
 "golang.org/x/sys/windows"
)
var (
 bcrypt = syscall.NewLazyDLL("bcrypt.dll")
 procBCryptOpenAlgorithmProvider = bcrypt.NewProc("BCryptOpenAlgorithmProvider")
 procBCryptImportKeyPair = bcrypt.NewProc("BCryptImportKeyPair")
 procBCryptDestroyKey = bcrypt.NewProc("BCryptDestroyKey")
 crypt32 = syscall.NewLazyDLL("crypt32.dll")
 procCryptDecodeObjectEx = crypt32.NewProc("CryptDecodeObjectEx")
)
const (
 BCRYPT_RSA_ALGORITHM = "RSA"
 MS_PRIMITIVE_PROVIDER = "Microsoft Primitive Provider"
 BCRYPT_RSAPUBLIC_BLOB = "RSAPUBLICBLOB"
 BCRYPT_RSAPUBLIC_MAGIC = 0x31415352 // 'RSA1'
 X509_ASN_ENCODING = 0x00000001
)
type BCRYPT_RSAKEY_BLOB struct {
 Magic uint32
 BitLength uint32
 cbPublicExp uint32
 cbModulus uint32
 cbPrime1 uint32
 cbPrime2 uint32
}
type CRYPT_ALGORITHM_IDENTIFIER struct {
 pszObjId *byte
 Parameters CRYPT_OBJID_BLOB
}
type CRYPT_OBJID_BLOB struct {
 CbData uint32
 PbData *byte
}
type CRYPT_BIT_BLOB struct {
 CbData uint32
 PbData *byte
 UnusedBits uint32
}
type CERT_PUBLIC_KEY_INFO struct {
 Algorithm CRYPT_ALGORITHM_IDENTIFIER
 PublicKey CRYPT_BIT_BLOB
}
func main() {
 // Load the certificate from cert.pem file
 certPEM, err := os.ReadFile("cert.pem")
 if err != nil {
 fmt.Printf("Failed to read certificate file: %v\n", err)
 return
 }
 // Decode the PEM format to get the DER-encoded certificate
 block, _ := pem.Decode(certPEM)
 if block == nil {
 fmt.Println("Failed to decode PEM block")
 return
 }
 certData := block.Bytes
 // Extract the public key info from the certificate
 var publicKeyInfo *CERT_PUBLIC_KEY_INFO
 var publicKeyInfoLen uint32
 r, _, err := procCryptDecodeObjectEx.Call(
 X509_ASN_ENCODING,
 uintptr(unsafe.Pointer(syscall.StringBytePtr("X509_PUBLIC_KEY_INFO"))),
 uintptr(unsafe.Pointer(&certData[0])),
 uintptr(len(certData)),
 0,
 0,
 uintptr(unsafe.Pointer(&publicKeyInfo)),
 uintptr(unsafe.Pointer(&publicKeyInfoLen)),
 )
 if r == 0 {
 fmt.Printf("CryptDecodeObjectEx failed: %v\n", err)
 return
 }
 // Open an algorithm provider
 var hAlg windows.Handle
 r, _, err = procBCryptOpenAlgorithmProvider.Call(
 uintptr(unsafe.Pointer(&hAlg)),
 uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(BCRYPT_RSA_ALGORITHM))),
 uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(MS_PRIMITIVE_PROVIDER))),
 0,
 )
 if r != 0 {
 fmt.Printf("BCryptOpenAlgorithmProvider failed: 0x%X\n", r)
 return
 }
 defer procBCryptDestroyKey.Call(uintptr(hAlg))
 // Prepare the BCRYPT_RSAKEY_BLOB structure
 pubKeyData := (*[1 << 30]byte)(unsafe.Pointer(publicKeyInfo.PublicKey.PbData))[:publicKeyInfo.PublicKey.CbData:publicKeyInfo.PublicKey.CbData]
 rsaKeyBlob := BCRYPT_RSAKEY_BLOB{
 Magic: BCRYPT_RSAPUBLIC_MAGIC,
 BitLength: uint32(len(pubKeyData) * 8),
 cbPublicExp: uint32(len(pubKeyData)),
 cbModulus: uint32(len(pubKeyData)),
 }
 // Import the public key
 var hKey windows.Handle
 r, _, err = procBCryptImportKeyPair.Call(
 uintptr(hAlg),
 0,
 uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(BCRYPT_RSAPUBLIC_BLOB))),
 uintptr(unsafe.Pointer(&hKey)),
 uintptr(unsafe.Pointer(&rsaKeyBlob)),
 uintptr(unsafe.Sizeof(rsaKeyBlob)),
 0,
 )
 if r != 0 {
 fmt.Printf("BCryptImportKeyPair failed: 0x%X\n", r)
 return
 }
 defer procBCryptDestroyKey.Call(uintptr(hKey))
 fmt.Println("Public key imported successfully")
}
asked Apr 12, 2025 at 17:44

0

Know someone who can answer? Share a link to this question via email, Twitter, or Facebook.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.