Go生成x509相关证书

一、简介

二、证书工具类

①保存证书到文件

func saveCertificateToFile(certBytes []byte, certType, filePath string, perm os.FileMode) error {
    err := os.MkdirAll(filepath.Dir(configrootpath+filePath), 0755)
    if err != nil {
        fmt.Printf("failed to create directory: %v", err)
    }
    certPEM := pem.EncodeToMemory(&pem.Block{Type: certType, Bytes: certBytes})
    err = os.WriteFile(configrootpath+filePath, certPEM, perm)
    if err != nil {
        return err
    }
    return nil
}

三、生成自签名CA证书

func generateCACertificate(country, province, city string) []byte {
    caKey, err := rsa.GenerateKey(rand.Reader, 4096)
    if err != nil {
        log.Fatal(err)
    }

    // 创建CA证书
    caCert := &x509.Certificate{
        SerialNumber: big.NewInt(1),
        Subject:      pkix.Name{CommonName: "test.top"},
        NotBefore:    time.Now(),
        NotAfter:     time.Now().AddDate(100, 0, 0),
        IsCA:         true,
        KeyUsage:     x509.KeyUsageDigitalSignature | x509.KeyUsageCRLSign | x509.KeyUsageCertSign,
        // 基本约束
        BasicConstraintsValid: true,
        // 证书最大路径,该级 CA 能签发子 CA 的证书链路径深度
        MaxPathLen: 0,
        // 不允许该 CA 签发子 CA
        MaxPathLenZero: false,
        // OCSP 响应服务器
        OCSPServer: nil,
        // CRL 分发点
        CRLDistributionPoints: nil,
    }

    // CA扩展配置
    caCert.SubjectKeyId = []byte{1, 2, 3, 4, 5}
    caCert.AuthorityKeyId = []byte{1, 2, 3, 4, 5}

    // 生成CA证书
    caCertBytes, err := x509.CreateCertificate(rand.Reader, caCert, caCert, caKey.Public(), caKey)
    if err != nil {
        log.Fatal(err)
    }

    // 保存CA证书到文件
    err = saveCertificateToFile(caCertBytes, "CERTIFICATE", "pki/ca.crt", 0644)
    if err != nil {
        log.Fatal(err)
    }
    // 保存CA私钥到文件
    caKeyPEMBytes := x509.MarshalPKCS1PrivateKey(caKey)
    err = saveCertificateToFile(caKeyPEMBytes, "RSA PRIVATE KEY", "pki/ca.key", 0600)
    if err != nil {
        log.Fatal(err)
    }
    return caCertBytes
}

四、自签CA证书签署服务端证书

func generateServerCertificate(serverName string) {
    caCert, caKey := getCACertificateAndKey()

    serverKey, err := rsa.GenerateKey(rand.Reader, 4096)
    if err != nil {
        log.Fatal(err)
    }
    serverCert := &x509.Certificate{
        SerialNumber:          big.NewInt(2),
        Subject:               pkix.Name{CommonName: serverName},
        NotBefore:             time.Now(),
        NotAfter:              time.Now().AddDate(1, 0, 0),
        KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
        ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
        BasicConstraintsValid: true,
    }
    serverCertBytes, err := x509.CreateCertificate(rand.Reader, serverCert, caCert, serverKey.Public(), caKey)
    if err != nil {
        log.Fatal(err)
    }

    // 保存服务端证书到文件
    err = saveCertificateToFile(serverCertBytes, "CERTIFICATE", "pki/server.crt", 0644)
    if err != nil {
        log.Fatal(err)
    }

    // 保存服务端私钥到文件
    serverKeyPEMBytes, err := x509.MarshalPKCS8PrivateKey(serverKey)
    if err != nil {
        log.Fatal(err)
    }
    err = saveCertificateToFile(serverKeyPEMBytes, "RSA PRIVATE KEY", "pki/server.key", 0600)
    if err != nil {
        log.Fatal(err)
    }
}

五、自签CA证书签署客户端证书

func generateClientCertificate(clientName string) {
    caCert, caKey := getCACertificateAndKey()

    serialNumber, _ := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128))

    // 生成客户端证书私钥
    privateKey, _ := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
    notBefore := time.Now()
    notAfter := notBefore.AddDate(50, 0, 0)
    clientCertTemplate := x509.Certificate{
        SerialNumber:          serialNumber,
        Subject:               pkix.Name{CommonName: clientName},
        NotBefore:             notBefore,
        NotAfter:              notAfter,
        KeyUsage:              x509.KeyUsageDataEncipherment | x509.KeyUsageDigitalSignature,
        ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
        BasicConstraintsValid: true,
    }
    clientCertBytes, err := x509.CreateCertificate(rand.Reader, &clientCertTemplate, caCert, &privateKey.PublicKey, caKey)
    if err != nil {
        log.Fatal(err)
    }
    // 保存客户端证书和证书私钥到文件
    saveCertificateToFile(clientCertBytes, "CERTIFICATE", "pki/clients/"+clientName+".crt", 0644)
    clientKeyPEMBytes, _ := x509.MarshalECPrivateKey(privateKey)
    saveCertificateToFile(clientKeyPEMBytes, "EC PRIVATE KEY", "pki/clients/"+clientName+".key", 0600)
    indexFile, err := os.OpenFile(configrootpath+"pki/index.txt", os.O_APPEND|os.O_WRONLY, 0644)
    if err != nil {
        log.Fatal(err)
    }
    defer indexFile.Close()

    serialNumberHex := fmt.Sprintf("%X", clientCertTemplate.SerialNumber)
    clientCertString := "V " + serialNumberHex + " " + clientCertTemplate.NotBefore.Format("060102150405Z") + " " + clientCertTemplate.NotAfter.Format("060102150405Z") + " unknown /CN=" + clientName + "\n"
    if _, err := indexFile.WriteString(clientCertString); err != nil {
        log.Fatal(err)
    }

    clientConfig := readFile(configrootpath + "common-client-config.txt")

    // 在变量中追加内容
    additionalContent := "<cert>\n" + string(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: clientCertBytes})) + "</cert>\n<key>\n" + string(pem.EncodeToMemory(&pem.Block{Type: "EC PRIVATE KEY", Bytes: clientKeyPEMBytes})) + "</key>\n"
    clientConfig = append(clientConfig, additionalContent...)
    os.WriteFile(configrootpath+"../client/"+clientName+".ovpn", clientConfig, 0644)
}

六、验证证书

参考:

Copyright Curiouser all right reserved,powered by Gitbook该文件最后修改时间: 2024-08-05 22:26:06

results matching ""

    No results matching ""