Перейти к содержимому
ecdsa.com
Go crypto/x509Go

Сообщение об ошибке

x509: failed to parse private key (use ParsePKCS1PrivateKey instead for this key format)

Также выводится как

  • x509: failed to parse private key (use ParseECPrivateKey instead for this key format)
  • x509: failed to parse private key (use ParsePKCS8PrivateKey instead for this key format)
  • x509: failed to parse public key (use ParsePKCS1PublicKey instead for this key format)

Функция в скобках зависит от того, что обнаружил Go: `ParsePKCS1PrivateKey`, `ParseECPrivateKey` или `ParsePKCS8PrivateKey`. Аналогичная ошибка для открытого ключа: «x509: failed to parse public key (use ParsePKCS1PublicKey instead for this key format)». Байты, которые не подходят ни к одному из форматов, вместо этого дают `asn1: structure error`.

Go crypto/x509 — ParsePKCS8PrivateKey / ParsePKCS1PrivateKey / ParseECPrivateKey / ParsePKIXPublicKey

Что это означает

Вы передали DER-байты закрытого ключа в одном контейнере парсеру для другого контейнера, и Go распознал, какой это контейнер на самом деле. Распространены три кодировки: PKCS#8 (`-----BEGIN PRIVATE KEY-----`, любой алгоритм), PKCS#1 (`-----BEGIN RSA PRIVATE KEY-----`, только RSA) и SEC 1 (`-----BEGIN EC PRIVATE KEY-----`, только EC). Подсказка в скобках называет функцию, которая разберёт ваши байты. С самим ключом всё в порядке.

Почему это происходит

Как исправить

  1. 1.

    Выбирайте парсер по типу PEM

    Метка PEM указывает на контейнер. Выбирайте парсер по `block.Type`, а не рассчитывайте на один формат.

    go
    func parsePrivateKeyPEM(data []byte) (crypto.Signer, error) {
    	block, _ := pem.Decode(data)
    	if block == nil {
    		return nil, errors.New("no PEM block found")
    	}
    	switch block.Type {
    	case "PRIVATE KEY": // PKCS#8: RSA, ECDSA, Ed25519, X25519
    		key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
    		if err != nil {
    			return nil, err
    		}
    		signer, ok := key.(crypto.Signer)
    		if !ok {
    			return nil, fmt.Errorf("%T cannot sign", key)
    		}
    		return signer, nil
    	case "RSA PRIVATE KEY": // PKCS#1
    		return x509.ParsePKCS1PrivateKey(block.Bytes)
    	case "EC PRIVATE KEY": // SEC 1
    		return x509.ParseECPrivateKey(block.Bytes)
    	default:
    		return nil, fmt.Errorf("unsupported PEM type %q", block.Type)
    	}
    }
  2. 2.

    Приведите ключи к PKCS#8 и SPKI

    PKCS#8 для закрытых ключей и SPKI для открытых ключей подходят для любого алгоритма и любой современной библиотеки. Преобразуйте ключи один раз, при их подготовке и развёртывании.

    bash
    # Normalise any private key to PKCS#8 ("-----BEGIN PRIVATE KEY-----")
    openssl pkcs8 -topk8 -nocrypt -in legacy.pem -out key.pk8.pem
    # Public keys: PKCS#1 "RSA PUBLIC KEY" -> SPKI "PUBLIC KEY"
    openssl rsa -RSAPublicKey_in -in rsa-pub.pem -pubout -out spki.pem

Связанные ошибки

Открыть всю базу ошибок подписей