SupportsCertificate не выдает взаимно поддерживаемых версий протоколов для X509Certificate, извлеченных из pfx

#go #ssl #post #x509certificate

#Вперед #ssl #Публикация #x509certificate

Вопрос:

С помощью следующего кода я создаю сертификат TLS

 func loadCert() tls.Certificate {
    b, err := ioutil.ReadFile(fileName)
    if err != nil {
        log.Fatalln("failed to find / open cert file", err)
    }
    p, c, err1 := pkcs12.Decode(b, password)
    if err1 != nil {
        log.Fatalln("Failed to read cert content", err1)
    }
    tlsCert := tls.Certificate{
        PrivateKey: p,
        Leaf:       c,
    }
    return tlsCert
}
  

А затем с помощью NewCertPool() я добавляю это в пул

 func makeRequest(){    
    // Loading cert
    cert := loadCert()
    caCertPool := x509.NewCertPool()

    caCertPool.AddCert(cert.Leaf)

    tConfig := amp;tls.Config{
        RootCAs: caCertPool,
        PreferServerCipherSuites: true,
        InsecureSkipVerify:       false,
        Certificates:             []tls.Certificate{cert},
    }

    tr := amp;http.Transport{
      TLSClientConfig: tConfig,
    }

    client := http.Client{
        Transport: tr,
    }
    request, reqError := http.NewRequest("POST", url, bytes.NewBuffer(dataToPost))
    if reqError != nil {
         log.Fatalln(" failed with error", reqError)
    }
    request.Header.Set("Accept", "*/*")
    request.Header.Set("Connection", "keep-alive")
    request.Header.Add("Content-Type", "text/xml;charset=UTF-8")
    res, dErr := client.Do(request)
    if dErr != nil {
        log.Fatalln("Failed to make request", dErr)
    } else {
        log.Println(res.StatusCode)
    }
}
  

SupportCertificate выдает

нет взаимно поддерживаемых версий протоколов

Тот же сертификат отлично работает с такими инструментами, как Postman. Если я удалю проверку с помощью этой функции supportCertificate и попытаюсь выполнить POST-вызов, сервер сообщает, что сертификат клиента не найден, несмотря на добавление его в транспорт выше. И на стороне клиента я получаю сообщение об ошибке, что соединение было сброшено и

x509: сертификат, подписанный неизвестным органом

Чтобы исправить это, я попытался использовать SystemCertPool() , после чего код не выполняется в Windows с ошибкой SystemCertPool не найден. В Docker или на виртуальной машине происходит сбой с

соединение было сброшено одноранговым узлом

Я действительно в недоумении, чего мне не хватает, был бы признателен за помощь в этом.

Я уже просмотрел действительно полезные сообщения о том, как можно настроить TLS и как сертификаты CA могут быть добавлены в новый пул. Но я все еще, кажется, что-то упускаю.

Комментарии:

1. ClientHelloInfo.SupportsCertificate необходимо вызвать во ClientHelloInfo время или после подтверждения связи TLS. Вы вызываете его для неинициализированного объекта. Удалите это и покажите часть кода, которая выполняет фактическую публикацию. Для пула CA пул системных сертификатов не работает в Windows, но есть обходной путь (вам нужно будет их найти)

2. Вы также не должны добавлять свой собственный сертификат клиента в пул, вам нужен центр сертификации, который может проверять сертификат сервера (либо в системном пуле, либо в пользовательском, который вы укажете). Вам также не нужно устанавливать ClientAuth , это настройка на стороне сервера.

3. @Marc я отредактировал свой вопрос с помощью кода для запроса POST. Как вы упомянули, я удалил ClientHello и cert из пула. Я могу смириться с тем, что это не работает в Windows, это не моя основная платформа. Итак, я переключил его на SystemCertPool и повторно выполнил его на виртуальной машине (Ubuntu 18). выдает> чтение tcp <localIP>:порт -> <serverIP>:<порт>: чтение: сброс соединения одноранговым узлом

4. Что говорит серверная сторона?

5. @Marc у меня нет доступа к серверу, это сервер внешнего провайдера. 🙁

Ответ №1:

Вы можете попробовать использовать свой http.Client с настроенным tls.Config , где вы переопределили корневой центр сертификации. Например:

 http.Client{
    Transport: amp;http.Transport{
        TLSClientConfig: amp;tls.Config{
            RootCAs: caPool,
        },
},
  

где caPool можно получить как

 caPool, err := x509.SystemCertPool()
if err != nil {
    return nil, fmt.Errorf("SystemCertPool() error: %v", err)
}
if caPool == nil {
    caPool = x509.NewCertPool()
}

certs, err := ioutil.ReadFile(path)
if err != nil {
    return nil, fmt.Errorf("failed to read CA from file '%q': %v", path, err)
}

if ok := caPool.AppendCertsFromPEM(certs); !ok {
    return nil, fmt.Errorf("failed to append local CA to root cert pool")
}
  

Комментарии:

1. Спасибо. Но это выглядит почти так же, как то, что я делаю. Единственное различие, которое я вижу, заключается в том, что вы проверяете, является ли SystemCertPool нулевым или нет. Очевидно, что это не работает в Windows, но мои тесты на docker (alpine image) и ubuntu 18 VM не возвращают нулевой системный пул.