LoginSignup
1
0

More than 3 years have passed since last update.

GolangでPKI入門 - 4

Last updated at Posted at 2020-10-28

1. この記事の対象の人

  • Golang で、証明書失効リスト( CRL )を作りたい人

2. 概要

この記事では、
1. Go で秘密鍵と証明書を生成
2. Go で失効させる証明書のリストを生成
3. Go で Issuing Distribution Point のExtensionを作成
4. Go で証明書失効リスト( CRL )を作成
5. OpenSSL で証明書失効リスト( CRL )の中身を確認
します。

3. Golang で自己署名 CA 証明書と秘密鍵を作成

証明書失効リストを発行する自己署名 CA の「証明書」と「秘密鍵」を作成します。
詳細な説明は、GolangでPKI入門 - 2 を参照ください。
証明書失効リスト作成時に引数で必要になるので、秘密鍵はDER形式にしておきます。


    //PrivateKey of Self Sign CA Certificate
    privateCaKey, err := rsa.GenerateKey(rand.Reader, 2048)
    publicCaKey := privateCaKey.Public()

    //[RFC5280]
    subjectCa := pkix.Name{
        CommonName:         "ca01",
        OrganizationalUnit: []string{"Example Org Unit"},
        Organization:       []string{"Example Org"},
        Country:            []string{"JP"},
    }

    caTpl := &x509.Certificate{
        SerialNumber:          big.NewInt(1),
        Subject:               subjectCa,
        NotAfter:              time.Date(2022, 1, 1, 0, 0, 0, 0, time.UTC),
        NotBefore:             time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC),
        IsCA:                  true,
        KeyUsage:              x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
        BasicConstraintsValid: true,
    }

    //Self Sign CA Certificate
    caCertificate, err := x509.CreateCertificate(rand.Reader, caTpl, caTpl, publicCaKey, privateCaKey)


    //Convert to ASN.1 DER encoded form
    derCaCert, err = x509.ParseCertificate(caCertificate)
    if err != nil {
        log.Fatalf("ERROR:%v\n", err)
    }

4. Golang で証明書失効リストを作成

失効させる証明書のリストを作成

    var rcs []pkix.RevokedCertificate
    rc := pkix.RevokedCertificate{
        SerialNumber:   big.NewInt(100),
        RevocationTime: time.Now(),
    }

    rcs = append(rcs, rc)

    rc = pkix.RevokedCertificate{
        SerialNumber:   big.NewInt(108),
        RevocationTime: time.Now(),
    }

    rcs = append(rcs, rc)

ここでは、シリアルが100と108の証明書を失効させます。

証明書失効リストの crlExtensions に Issuing Distribution Point を追加

Go で証明書失効リストを作成するときに利用する x509.RevocationList には、直接 Issuing Distribution Point を追加するFieldはありません。
別途 Issuing Distribution Point 用の構造体を作成して、Extensionに追加してやる必要があります。
RFC5280 では、Issuing Distribution Pointは以下のように定義されています。

   id-ce-issuingDistributionPoint OBJECT IDENTIFIER ::= { id-ce 28 }

   IssuingDistributionPoint ::= SEQUENCE {
        distributionPoint          [0] DistributionPointName OPTIONAL,
        onlyContainsUserCerts      [1] BOOLEAN DEFAULT FALSE,
        onlyContainsCACerts        [2] BOOLEAN DEFAULT FALSE,
        onlySomeReasons            [3] ReasonFlags OPTIONAL,
        indirectCRL                [4] BOOLEAN DEFAULT FALSE,
        onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE }

   DistributionPointName ::= CHOICE {
        fullName                [0]     GeneralNames,
        nameRelativeToCRLIssuer [1]     RelativeDistinguishedName }

   GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName

   GeneralName ::= CHOICE {
        otherName                       [0]     OtherName,
        rfc822Name                      [1]     IA5String,
        dNSName                         [2]     IA5String,
        x400Address                     [3]     ORAddress,
        directoryName                   [4]     Name,
        ediPartyName                    [5]     EDIPartyName,
        uniformResourceIdentifier       [6]     IA5String,
        iPAddress                       [7]     OCTET STRING,
        registeredID                    [8]     OBJECT IDENTIFIER }

上記に従い、issuingDistributionPoint と distributionPointName を 以下の Go の構造体として定義しました。

// RFC5280, 5.2.5
type issuingDistributionPoint struct {
    DistributionPoint          distributionPointName `asn1:"optional,tag:0"`
    OnlyContainsUserCerts      bool                  `asn1:"optional,tag:1"`
    OnlyContainsCACerts        bool                  `asn1:"optional,tag:2"`
    OnlySomeReasons            asn1.BitString        `asn1:"optional,tag:3"`
    IndirectCRL                bool                  `asn1:"optional,tag:4"`
    OnlyContainsAttributeCerts bool                  `asn1:"optional,tag:5"`
}

type distributionPointName struct {
    FullName     []asn1.RawValue  `asn1:"optional,tag:0"`
    RelativeName pkix.RDNSequence `asn1:"optional,tag:1"`
}

distributionPointName の FullName フィールドの型は GeneralNames です。
GeneralName の uniformResourceIdentifier で証明書失効リストの取得先を指定したいので、
asn1.RawValue 型で以下のように設定
Class: 2
Context-specific ( asn1.RawValue の定義による)
Tag: 6
GeneralName の6番目つまり uniformResourceIdentifier
Bytes: []byte("http://www.example.com/example.crl")
uniformResourceIdentifier の エンコーディングは IA5String です。ただ、crl への URI で使われている範囲の文字列は IA5String と UTF8 で同じbyteになるので直接 byte 配列として渡しています。

    dp := distributionPointName{
        FullName: []asn1.RawValue{
            {Tag: 6, Class: 2, Bytes: []byte("http://www.example.com/example.crl")},
        },
    }

Extension に作成した IssuingDistributionPoint を設定します。


var oidExtensionIssuingDistributionPoint = []int{2, 5, 29, 28}

    idp := issuingDistributionPoint{
        DistributionPoint: dp,
    }

    v, err := asn1.Marshal(idp)

    cdpExt := pkix.Extension{
        Id:       oidExtensionIssuingDistributionPoint,
        Critical: true,
        Value:    v,
    }

x509.RevocationList 構造体の設定

x509.RevocationList 構造体に設定したい値を入れていきます。

    crlTpl := &x509.RevocationList{
        SignatureAlgorithm:  x509.SHA256WithRSA,
        RevokedCertificates: rcs,
        Number:              big.NewInt(2),
        ThisUpdate:          time.Now(),
        NextUpdate:          time.Now().Add(24 * time.Hour),
        ExtraExtensions:     []pkix.Extension{cdpExt},
    }

証明書失効リストを作成

証明書失効リストを発行します

    var derCrl []byte
    derCrl, err = x509.CreateRevocationList(rand.Reader, crlTpl, derCaCert, privateCaKey)
    if err != nil {
        log.Fatalf("ERROR:%v\n", err)
    }

    f, err = os.Create("ca01.crl")
    if err != nil {
        log.Fatalf("ERROR:%v\n", err)
    }

    err = pem.Encode(f, &pem.Block{Type: "X509 CRL", Bytes: derCrl})
    if err != nil {
        log.Fatalf("ERROR:%v\n", err)
    }
    err = f.Close()

5. 証明書失効リストを確認する

発行した証明書失効リストを Openssl で確認します。設定した要素がすべて入っていますね。

$ openssl crl -inform pem -in example.crl -text
Certificate Revocation List (CRL):
        Version 2 (0x1)
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = JP, O = Example Org, OU = Example Org Unit, CN = ca01
        Last Update: Oct 24 04:16:04 2020 GMT
        Next Update: Oct 25 04:16:04 2020 GMT
        CRL extensions:
            X509v3 Authority Key Identifier:
                keyid:0A:42:8D:9B:23:A9:77:11:FF:FD:0F:CC:58:F4:36:F4:98:06:7F:28

            X509v3 CRL Number:
                2
            X509v3 Issuing Distribution Point: critical
                Full Name:
                  URI:http://www.example.com/example.crl

Revoked Certificates:
    Serial Number: 64
        Revocation Date: Oct 24 04:16:04 2020 GMT
    Serial Number: 6C
        Revocation Date: Oct 24 04:16:04 2020 GMT
    Signature Algorithm: sha256WithRSAEncryption
         6c:0d:23:e8:50:bf:84:ae:10:85:3e:43:28:0f:43:fd:58:cb:
         83:8c:7c:a8:5c:7d:78:71:f1:0c:03:97:43:88:8c:32:02:5c:
         a6:6c:e2:a4:7d:94:56:08:a8:9c:17:95:b4:be:11:bb:65:52:
         43:25:de:c0:d5:d0:df:ac:0f:ca:8c:a7:23:82:19:12:e2:9d:
         49:83:9e:ca:bc:2e:f3:60:79:39:47:cb:ed:17:52:25:9f:42:
         26:9e:1b:67:5f:af:e1:3a:14:67:5f:4f:de:10:c5:32:03:7f:
         40:a0:b6:bc:3f:05:33:73:91:0b:73:4e:f2:3c:be:b0:e4:63:
         e0:d0:81:6e:91:14:d9:04:35:21:3e:22:1e:31:bd:47:40:c9:
         69:f0:e5:57:bc:c3:2c:ae:b8:06:38:35:f1:59:6f:45:2c:45:
         08:2e:63:49:ab:f5:54:0b:54:d2:a8:fc:62:ea:a5:46:62:28:
         a9:89:76:96:cf:47:28:3d:81:c3:e9:fb:ce:54:a8:07:71:6d:
         c6:d8:b7:e7:33:b0:05:df:c4:79:56:e1:99:ed:9f:33:f8:15:
         b9:32:4e:82:4c:0c:a7:a5:23:d4:f7:e1:94:26:2b:e0:55:1a:
         38:f6:72:21:a9:e0:29:06:80:9a:05:e3:43:c2:4a:dd:74:c6:
         d6:79:ec:9d
-----BEGIN X509 CRL-----
MIICKDCCARACAQEwDQYJKoZIhvcNAQELBQAwTTELMAkGA1UEBhMCSlAxFDASBgNV
BAoTC0V4YW1wbGUgT3JnMRkwFwYDVQQLExBFeGFtcGxlIE9yZyBVbml0MQ0wCwYD
VQQDEwRjYTAxFw0yMDEwMjQwNDE2MDRaFw0yMDEwMjUwNDE2MDRaMCgwEgIBZBcN
MjAxMDI0MDQxNjA0WjASAgFsFw0yMDEwMjQwNDE2MDRaoGUwYzAfBgNVHSMEGDAW
gBQKQo2bI6l3Ef/9D8xY9Db0mAZ/KDAKBgNVHRQEAwIBAjA0BgNVHRwBAf8EKjAo
oCagJIYiaHR0cDovL3d3dy5leGFtcGxlLmNvbS9leGFtcGxlLmNybDANBgkqhkiG
9w0BAQsFAAOCAQEAbA0j6FC/hK4QhT5DKA9D/VjLg4x8qFx9eHHxDAOXQ4iMMgJc
pmzipH2UVgionBeVtL4Ru2VSQyXewNXQ36wPyoynI4IZEuKdSYOeyrwu82B5OUfL
7RdSJZ9CJp4bZ1+v4ToUZ19P3hDFMgN/QKC2vD8FM3ORC3NO8jy+sORj4NCBbpEU
2QQ1IT4iHjG9R0DJafDlV7zDLK64Bjg18VlvRSxFCC5jSav1VAtU0qj8YuqlRmIo
qYl2ls9HKD2Bw+n7zlSoB3Ftxti35zOwBd/EeVbhme2fM/gVuTJOgkwMp6Uj1Pfh
lCYr4FUaOPZyIangKQaAmgXjQ8JK3XTG1nnsnQ==
-----END X509 CRL-----

6. コード

コードはこちら
https://github.com/tardevnull/gopkicookbook4

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0