Функция x509.CreateCertificate

Функция x509.CreateCertificate создает новый сертификат X.509. Первый параметр - rand.Reader, предоставляющий криптостойкий генератор случайных чисел. Второй параметр - шаблон сертификата, описывающий поля создаваемого сертификата. Третий параметр - родительский сертификат (может быть самим собой для самоподписанного). Четвертый параметр - открытый ключ создаваемого сертификата. Пятый параметр - приватный ключ для подписи сертификата.

Синтаксис

gox509.CreateCertificate(rand io.Reader, template, parent *x509.Certificate, pub any, priv any) ([]byte, error)

Пример

Создадим самоподписанный сертификат X.509 для тестовых целей:

gopackage main

import (
  "crypto/rand"
  "crypto/rsa"
  "crypto/x509"
  "crypto/x509/pkix"
  "fmt"
  "math/big"
  "time"
)

func main() {
  // Генерация приватного ключа RSA
  privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
  if err != nil {
    fmt.Println("Error generating key:", err)
    return
  }

  // Шаблон сертификата
  template := &x509.Certificate{
    SerialNumber: big.NewInt(1),
    Subject: pkix.Name{
      CommonName: "example.com",
    },
    NotBefore: time.Now(),
    NotAfter:  time.Now().Add(time.Hour * 24 * 365),
  }

  // Создание самоподписанного сертификата
  certBytes, err := x509.CreateCertificate(
    rand.Reader,
    template,
    template,
    &privateKey.PublicKey,
    privateKey,
  )
  if err != nil {
    fmt.Println("Error creating certificate:", err)
    return
  }

  fmt.Printf("Certificate created, length: %d bytes\n", len(certBytes))
}

Результат выполнения кода:

go"Certificate created, length: 1137 bytes"

Пример

Создадим сертификат с использованием родительского сертификата и приватного ключа:

gopackage main

import (
  "crypto/rand"
  "crypto/rsa"
  "crypto/x509"
  "crypto/x509/pkix"
  "fmt"
  "math/big"
  "time"
)

func main() {
  // Создание корневого (родительского) ключа и сертификата
  caKey, err := rsa.GenerateKey(rand.Reader, 2048)
  if err != nil {
    fmt.Println("Error generating CA key:", err)
    return
  }

  caTemplate := &x509.Certificate{
    SerialNumber: big.NewInt(1),
    Subject: pkix.Name{
      CommonName: "CA",
    },
    NotBefore: time.Now(),
    NotAfter:  time.Now().Add(time.Hour * 24 * 365),
  }

  caCertBytes, err := x509.CreateCertificate(
    rand.Reader,
    caTemplate,
    caTemplate,
    &caKey.PublicKey,
    caKey,
  )
  if err != nil {
    fmt.Println("Error creating CA certificate:", err)
    return
  }

  caCert, err := x509.ParseCertificate(caCertBytes)
  if err != nil {
    fmt.Println("Error parsing CA certificate:", err)
    return
  }

  // Создание клиентского ключа
  clientKey, err := rsa.GenerateKey(rand.Reader, 2048)
  if err != nil {
    fmt.Println("Error generating client key:", err)
    return
  }

  // Шаблон клиентского сертификата
  clientTemplate := &x509.Certificate{
    SerialNumber: big.NewInt(2),
    Subject: pkix.Name{
      CommonName: "client.example.com",
    },
    NotBefore: time.Now(),
    NotAfter:  time.Now().Add(time.Hour * 24 * 30),
  }

  // Создание сертификата, подписанного корневым
  clientCertBytes, err := x509.CreateCertificate(
    rand.Reader,
    clientTemplate,
    caCert,
    &clientKey.PublicKey,
    caKey,
  )
  if err != nil {
    fmt.Println("Error creating client certificate:", err)
    return
  }

  fmt.Printf("Client certificate created, length: %d bytes\n", len(clientCertBytes))
}

Результат выполнения кода:

go"Client certificate created, length: 1135 bytes"

Пример

Создание сертификата с различными расширениями (SAN, ключевые использования):

gopackage main

import (
  "crypto/rand"
  "crypto/rsa"
  "crypto/x509"
  "crypto/x509/pkix"
  "fmt"
  "math/big"
  "net"
  "time"
)

func main() {
  privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
  if err != nil {
    fmt.Println("Error generating key:", err)
    return
  }

  template := &x509.Certificate{
    SerialNumber: big.NewInt(1),
    Subject: pkix.Name{
      CommonName: "example.com",
    },
    DNSNames: []string{"example.com", "www.example.com"},
    IPAddresses: []net.IP{
      net.ParseIP("192.168.1.1"),
    },
    KeyUsage:  x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
    ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
    NotBefore:   time.Now(),
    NotAfter:  time.Now().Add(time.Hour * 24 * 365),
  }

  certBytes, err := x509.CreateCertificate(
    rand.Reader,
    template,
    template,
    &privateKey.PublicKey,
    privateKey,
  )
  if err != nil {
    fmt.Println("Error creating certificate:", err)
    return
  }

  fmt.Printf("Certificate with SAN created, length: %d bytes\n", len(certBytes))
}

Результат выполнения кода:

go"Certificate with SAN created, length: 1188 bytes"

Смотрите также

  • функцию x509.ParseCertificate,
    которая парсит DER-кодированный сертификат в структуру
  • функцию x509.ParsePKCS1PrivateKey,
    которая парсит приватный ключ RSA в формате PKCS#1
  • функцию pem.Encode,
    которая кодирует сертификат в формат PEM
  • функцию rsa.GenerateKey,
    которая генерирует пару ключей RSA