Go: HTTPS-запрос с использованием клиентского сертификата, хранящегося на смарт-карте (Windows) - PullRequest
0 голосов
/ 27 марта 2020

Чтобы выполнить аутентификацию сертификата клиента (взаимную аутентификацию), все примеры, которые я нашел, предполагают, что закрытый ключ доступен (например, из файла). Сертификат, содержащий закрытый и открытый ключ c, создается следующим образом:

cert, err := tls.LoadX509KeyPair("certs/client.pem", "certs/client.key")

Теперь я должен получить сертификат (и закрытый ключ, который, насколько я знаю, не может быть извлечен - подпись должно быть сделано через PKCS # 11) со смарт-карты. До сих пор мне удавалось перечислять сертификаты из хранилища сертификатов Windows:

store, err := syscall.UTF16PtrFromString("MY")
storeHandle, err := syscall.CertOpenSystemStore(0, store)
if err != nil {
    fmt.Println(syscall.GetLastError())
}

var certs []*x509.Certificate
var cert *syscall.CertContext
for {
    cert, err = syscall.CertEnumCertificatesInStore(storeHandle, cert)
    if err != nil {
        if errno, ok := err.(syscall.Errno); ok {
            if errno == CRYPT_E_NOT_FOUND {
                break
            }
        }
        fmt.Println(syscall.GetLastError())
    }
    if cert == nil {
        break
    }
    // Copy the buf, since ParseCertificate does not create its own copy.
    buf := (*[1 << 20]byte)(unsafe.Pointer(cert.EncodedCert))[:]
    buf2 := make([]byte, cert.Length)
    copy(buf2, buf)
    if c, err := x509.ParseCertificate(buf2); err == nil {
        for _, value := range c.ExtKeyUsage {
            if value == x509.ExtKeyUsageClientAuth {
                fmt.Println(c.Subject.CommonName)
                fmt.Println(c.Issuer.CommonName)
                certs = append(certs, c)
            }
        }
    }
}

Этот сертификат, полученный таким образом, действительно получен со SmartCard. При последующем использовании аутентификации происходит сбой:

cer:= tls.Certificate{Certificate: [][]byte{certs[0].Raw}, Leaf: certs[0],}

tlsConfig := &tls.Config{
    Certificates:       []tls.Certificate{cer},
    RootCAs:            caCertPool,
    InsecureSkipVerify: true,
}

transport := &http.Transport{TLSClientConfig: tlsConfig}

client := http.Client{
    Timeout:   time.Minute * 2,
    Transport: transport,
}

Я предполагаю, что сбоя следует ожидать, поскольку я не предоставил закрытый ключ.

Java (SunMSCAPI) и . NET кажется, что под обложками используется закрытый ключ на смарт-карте, например, я делаю то же самое, что и выше, и аутентификация "просто работает".

Есть ли способ добиться этого с помощью Go * * 1014

1 Ответ

1 голос
/ 27 марта 2020

Закрытый ключ, который вы указываете для tls.Certificate, может быть любым объектом, который реализует crypto.Signer, который согласно документации:

является интерфейсом для непрозрачного закрытого ключа, который может использоваться для Подписание операций. Например, ключ RSA хранится в аппаратном модуле.

и предназначен именно для этого вида использования.

Реализация интерфейса довольно проста, если у вас есть доступ к базовому ключу. thalesignite / crypto11 предоставляет такую ​​реализацию, например, для ключей PKCS # 11.

...