20210914のGoに関する記事は1件です。

GolangでPKI入門 - 5

1.この記事の対象の人 Golang で、属性※付きの証明書要求( CSR ) を作ってみたい人 ※証明書の X.509 certificate extensions 用途のための属性を付けます。 ※以下、証明書要求は CSR と呼称します。 2.概要 この記事の概要は以下の通りです。 1. Golang で SubjectAltName と KeyUsage の属性をもつ CSR を生成 2. OpenSSL でSubjectAltName と KeyUsage の属性をもつ CSR を作成 3. 作成したそれぞれの CSR の中身を比較 4. おまけ-- CSR の属性の ASN.1 データ構造の調査(詳しく知りたい人向け) 3.Golang で SubjectAltName と KeyUsage の属性をもつ CSR を生成 Golang でCSRは、CreateCertificateRequest関数で作成できます。 属性を追加する場合、templateで値を指定します。 SubjectAltName 属性は template の DNSNames EmailAddresses IPAddresses URIs に値を指定します。 DNSNames: []string{"www.example.com", "www.example.co.jp"}, KeyUsage 属性は template に直接指定することができません。 代わりにKeyUsage の pkix.Extension を作成し ExtraExtensions に Extension の1つとして指定します。 marshalKeyUsage関数は、x509 パッケージから移植しました。詳細はコードを参照ください。 var ku x509.KeyUsage ku = x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign | x509.KeyUsageCRLSign kex, err := marshalKeyUsage(ku) SubjectAltName と KeyUsage 属性を持った template は以下になります。 template := &x509.CertificateRequest{ PublicKeyAlgorithm: x509.RSA, PublicKey: publicKey, SignatureAlgorithm: x509.SHA256WithRSA, Subject: pkix.Name{ CommonName: "www.example.org", OrganizationalUnit: []string{"Example Org Unit"}, Organization: []string{"Example Org"}, Country: []string{"JP"}, }, DNSNames: []string{"www.example.com", "www.example.co.jp"}, ExtraExtensions: []pkix.Extension{kex}, } CSR を作成します。 //PKCS#10 Certification Request [RFC2986] csr, err := x509.CreateCertificateRequest(rand.Reader, template, privateKey) 4.OpenSSL で SubjectAltName と KeyUsage の属性をもつ CSR を作成 OpenSSL で属性をもつ CSR を作成する方法は幾つかあります。 ここでは SubjectAltName と KeyUsage の値を指定した cnf ファイルを作成し、そのファイルを引数に指定して OpenSSL コマンドを実行し CSR を作成します。 ここでは、 ext.cnf という名前の cnf ファイルを作成します。 [ req ] req_extensions = req_ext distinguished_name = req_distinguished_name prompt = no [ req_distinguished_name ] countryName = JP organizationName = Example Org organizationalUnitName = Example Org Unit commonName = www.example.org [ req_ext ] subjectAltName = @alt_names keyUsage = nonRepudiation, digitalSignature, keyEncipherment [alt_names] DNS.1 = www.example.com DNS.2 = www.example.co.jp OpenSSL コマンドを実行し CSR を作成します。 $ openssl req -new -config ext.cnf -newkey rsa:2048 -nodes -keyout ext.key -out opensslext.csr 5.作成したそれぞれの CSR の中身を比較 OpenSSLで作成した CSR の中身を表示します。 $ openssl req -text -noout -in opensslext.csr Certificate Request: Data: Version: 1 (0x0) Subject: C = JP, O = Example Org, OU = Example Org Unit, CN = www.example.org Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public-Key: (2048 bit) Modulus: 省略 Exponent: 65537 (0x10001) Attributes: Requested Extensions: X509v3 Subject Alternative Name: DNS:www.example.com, DNS:www.example.co.jp X509v3 Key Usage: Digital Signature, Non Repudiation, Key Encipherment Signature Algorithm: sha256WithRSAEncryption 省略 次に Golang で作成した CSR の中身を表示します。 $ openssl req -text -noout -in goExtPem.csr Certificate Request: Data: Version: 1 (0x0) Subject: C = JP, O = Example Org, OU = Example Org Unit, CN = www.example.org Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public-Key: (2048 bit) Modulus: 省略 Exponent: 65537 (0x10001) Attributes: Requested Extensions: X509v3 Subject Alternative Name: DNS:www.example.com, DNS:www.example.co.jp X509v3 Key Usage: Digital Signature, Non Repudiation, Key Encipherment Signature Algorithm: sha256WithRSAEncryption 省略 同じですね。Golangで正しく属性付き CSR が作成できたようです。 6.おまけ -- CSR の属性の ASN.1 データ構造の調査 以下 CSR の属性の ANS.1 データ構造について詳しく知りたい人向けとなります。興味のある人はどうぞ。 CSR は、RFC2986 では 以下のように定義されています。 [PKCS#10] https://datatracker.ietf.org/doc/html/rfc2986#section-4 CertificationRequestInfo ::= SEQUENCE { version INTEGER { v1(0) } (v1,...), subject Name, subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }}, attributes [0] Attributes{{ CRIAttributes }} } SubjectPublicKeyInfo { ALGORITHM : IOSet} ::= SEQUENCE { algorithm AlgorithmIdentifier {{IOSet}}, subjectPublicKey BIT STRING } PKInfoAlgorithms ALGORITHM ::= { ... -- add any locally defined algorithms here -- } Attributes { ATTRIBUTE:IOSet } ::= SET OF Attribute{{ IOSet }} CRIAttributes ATTRIBUTE ::= { ... -- add any locally defined attributes here -- } Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE { type ATTRIBUTE.&id({IOSet}), values SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{@type}) } 属性だけに注目すると、属性は attributes [0] Attributes{{ CRIAttributes }} Type が Context-specific[0] で Value が Attributes{{ CRIAttributes }} と定義されています。 Attributes{{ CRIAttributes }} は、Attributes{} のパラメタが CRIAttributes であることを意味します。 CRIAttributes は ATTRIBUTE クラスの Information Object Set です。 CRIAttributes 自体の定義は、 CRIAttributes ATTRIBUTE ::= { ... -- add any locally defined attributes here -- } と書いてあるので任意のようです。 次に Attributes の定義をみると Attributes { ATTRIBUTE:IOSet } ::= SET OF Attribute{{ IOSet }} Attributes は、 SET OF Attribute{{ IOSet }} と定義されています。 ここで、IOSet = CRIAttributes です。 次に SET OF の Value である Attribute は、 Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE { type ATTRIBUTE.&id({IOSet}), values SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{@type}) } と定義されています。これは、 SEQUENCE が type と valuesを持つ。 この時、type は [ ATTRIBUTE クラス の &id ] を持つ。 (ただし、&id は、CRIAttributes で定義された Information Object の集合の &id の値の範囲に拘束される) この時、values は SET SIZE(1..MAX) OF [ ATTRIBUTE クラスの &Type ] を持つ。 (ただし、&Type の値は typeで指定した値(= &id ) に対応する Information Object の &Type の値に拘束される) ※ Information object calss や 拘束(Constrain) の文法の詳細は以下を参照してください。 RFC6025 OSS Nokalva, Inc. 社の ASN.1 解説 ここで、RFC2986 の attributes の説明 には attributes is a collection of attributes providing additional information about the subject of the certificate. Some attribute types that might be useful here are defined in PKCS #9. An example is the challenge-password attribute, which specifies a password by which the entity may request certificate revocation. Another example is information to appear in X.509 certificate extensions (e.g. the extensionRequest attribute from PKCS #9). と書いてあります。 今回は、 X.509 certificate extensions 用に付加情報を属性に指定したいので、RFC2985 (PKCS#9) の Extension request を参照します。 Extension request は 5.4.2 Extension request The extensionRequest attribute type may be used to carry information about certificate extensions the requester wishes to be included in a certificate. extensionRequest ATTRIBUTE ::= { WITH SYNTAX ExtensionRequest SINGLE VALUE TRUE ID pkcs-9-at-extensionRequest } ExtensionRequest ::= Extensions The Extensions type is imported from [10]. [10] ISO/IEC 9594-8:1997: Information technology - Open Systems Interconnection - The Directory: Authentication framework. 1997. と定義されています。 ということで今回、 CRIAttributes で使用する Information Object は、extensionRequest になります。 ※余談ですがRFC2985 5.4節 に従えば、Information Object Set としての CRIAttributes はこう定義できるはず... CRIAttributes ATTRIBUTE ::= { challengePassword | extensionRequest | extendedCertificateAttributes , ... } ここで、Extensions の定義は、ISO/IEC 9594-8:1997 を参照せよと書いてあるので ISO/IEC 9594-8:1997 を参照すると Extensions は Extensions ::= SEQUENCE OF Extension Extension ::= SEQUENCE { extnId EXTENSION.&id ({ExtensionSet}), critical BOOLEAN DEFAULT FALSE, extnValue OCTET STRING -- contains a DER encoding of a value of type &ExtnType -- for the extension object identified by extnId -- } と定義されています。 以上から CSR に証明書の X.509 certificate extensions 用途の属性をつける場合、属性の ASN.1 データ構造の模式図は以下になるはずです。 Context-Specific[0] SET OF SEQUENCE ObjectIdentifier(Extension Request : 1.2.840.113549.1.9.14) SET OF SEQUENCE SEQUENCE ObjectIdentifier(X509v3 Subject Alternative Name : 2.5.29.15) BOOLEAN(FALSEの場合省略される) OCTET STRING SEQUENCE ObjectIdentifier(X509v3 Key Usage : 2.5.29.17) BOOLEAN(FALSEの場合省略される) OCTET STRING 確認のため、OpenSSL で属性付き CSR を asn1parse してみました。 $ openssl asn1parse -in goExtPem.csr 中略 395:d=2 hl=2 l= 77 cons: cont [ 0 ] 397:d=3 hl=2 l= 75 cons: SEQUENCE 399:d=4 hl=2 l= 9 prim: OBJECT :Extension Request 410:d=4 hl=2 l= 62 cons: SET 412:d=5 hl=2 l= 60 cons: SEQUENCE 414:d=6 hl=2 l= 45 cons: SEQUENCE 416:d=7 hl=2 l= 3 prim: OBJECT :X509v3 Subject Alternative Name 421:d=7 hl=2 l= 38 prim: OCTET STRING [HEX DUMP]:3024820F7777772E6578616D706C652E636F6D82117777772E6578616D706C652E636F2E6A70 461:d=6 hl=2 l= 11 cons: SEQUENCE 463:d=7 hl=2 l= 3 prim: OBJECT :X509v3 Key Usage 468:d=7 hl=2 l= 4 prim: OCTET STRING [HEX DUMP]:030205E0 以下略 上記結果を同じように ASN.1 のデータ構造図の模式図にしてみると Context-Specific[0] SEQUENCE ObjectIdentifier(Extension Request : 1.2.840.113549.1.9.14) SET OF SEQUENCE SEQUENCE ObjectIdentifier(X509v3 Subject Alternative Name : 2.5.29.15) BOOLEAN(FALSEの場合省略される) OCTET STRING SEQUENCE ObjectIdentifier(X509v3 Key Usage : 2.5.29.17) BOOLEAN(FALSEの場合省略される) OCTET STRING あれ... Context-Specific[0] の Value の SET OF がない...。 Context-Specific[0] の Value である SET OF は IMPLICIT になって SET OF の Type と Length が省略されてエンコードされています。改めてRFC 2986を確認すると IMPLICIT として定義されています。 7. コード コードはこちら
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む