LoginSignup
7
4

More than 1 year has passed since last update.

BouncyCastleで自己署名証明書を発行してみよう(Java)

Last updated at Posted at 2021-12-16

はじめに

JVM上でキーペアを作成してAWS Secrets Managerに秘密鍵を、ローカルに公開鍵証明書を保存したくなったりしたことありませんか?
私はあります。

ので、BouncyCastleを使ってそれをやってみました。

概要

BouncyCastle APIを使って以下を行います。

  • キーペアの発行
  • 公開鍵から自己署名証明書の作成

そもそもBouncyCastleとはなんぞや

BouncyCastleは、The Legion of the Bouncy Castleがサポートしている暗号化APIです。

JavaおよびC#で軽量の暗号化に関連するAPIが提供されており、「almost 20 years」(すごい!)と歴史の長いプロジェクトです。
2000年からなので21年ですね。

原義は風船でできたお城だそう。

何ができるのか

BouncyCastleを使うことで、暗号化に関連する処理を簡単に行うことができます。
例えばそう、キーペアを作成して自己署名証明書を作成するとかね。

やってみた

ということでやってみましょう。

準備

用意するものは以下2つです。

Bouncy Castle Provider

Bouncy Castle PKIX, CMS, EAC, TSP, PKCS, OCSP, CMP, and CRMF APIs

MavenなりGradleなりでライブラリを落としてきます。

その上で、セキュリティプロバイダにBouncyCastleが含まれていなければ追加します。

Provider provider = new BouncyCastleProvider();
Security.addProvider(provider);

キーペアを作成する

まずキーペアを作成します。
現在主流のRSAで2048bitにします。

KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
generator.initialize(2048);
KeyPair keyPair = generator.generateKeyPair();

キーペアから自己署名証明書を作成する

ここからがBouncyCastleの出番です。

その前に、X.509証明書とは

・・・の前に、X.509証明書がどのような構造になっているのか確認しておきましょう。

こちらに記載の通り、X.509証明書には以下の要素が必要になります。

  • 発行者(署名する側)
  • 主体者(署名される側)
  • 公開鍵
  • 署名

これらに加えて、有効期限の情報やシリアルナンバーも必要になります。

公開鍵証明書に必要な情報をそろえる

では本題に進んでいきましょう。

このX509v3CertificateBuilderを利用すればきわめて簡単に公開鍵証明書を作成できます。

X509v3CertificateBuilder(X500Name issuer, BigInteger serial, Date notBefore, Date notAfter, X500Name subject, SubjectPublicKeyInfo publicKeyInfo)

とある通り、

  • 発行者 X500Name
  • シリアルナンバー BigInteger
  • 有効期限開始日時 Date
  • 有効期限終了日時 Date
  • 主体者 X500Name
  • 公開鍵情報 SubjectPublicKeyInfo

が必要になるので、まずそれらを用意します。
今回作成するのは自己署名証明書なので、発行者と主体者は同じになります。

X.500に従って識別名を作成します。

X500Name dnName = new X500Name("cn=hoge, ou=fuga, o=\"Foo Co., Ltd.\", c=JP");

次にシリアルナンバーですが、これは世界中でユニークでなくても構いませんが、発行機関ごとにはユニークでなければなりません。

4.1.2.2  Serial number

   The serial number is an integer assigned by the CA to each
   certificate.  It MUST be unique for each certificate issued by a
   given CA (i.e., the issuer name and serial number identify a unique
   certificate).

ランダムなシリアルナンバーを作成します。
ランダムであることは必須ではありませんが、選択的プレフィックス攻撃を避けるためにはシリアルナンバーと有効期限を予測できない形が良いでしょう。

long serialNumber =new RandomDataGenerator().nextLong(1L, 10L);
BigInteger certSerialNumber = new BigInteger(Long.toString(serialNumber));

次に有効期限です。
とりあえず発行した今日から有効にしたいので、システムミリ秒を使います。

long now = System.currentTimeMillis();
Date notBefore = new Date(now);

有効期限の終了日は開始日に任意の年数を足します。(ここではとりあえず3年)

Calendar calendar = Calendar.getInstance();
calendar.setTime(notBefore);
calendar.add(Calendar.YEAR, 3);
Date notAfter = calendar.getTime();

最後に署名対象になる公開鍵の情報です。

SubjectPublicKeyInfo subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded());

これで X509v3CertificateBuilder に必要な、

  • 発行者 X500Name
  • シリアルナンバー BigInteger
  • 有効期限開始日時 Date
  • 有効期限終了日時 Date
  • 主体者 X500Name
  • 公開鍵情報 SubjectPublicKeyInfo

の情報がそろったので、いよいよ署名処理に進みます。

署名する

まず、先ほど用意したオブジェクトをビルダーに渡します。

X509v3CertificateBuilder certificateBuilder = new X509v3CertificateBuilder(dnName, certSerialNumber, notBefore, notAfter, dnName, subjectPublicKeyInfo);

次に、署名オペレータである ContentSigner の実装クラスを初期化します。
このとき、JCA(Java Cryptography Architecture)を利用し、準備でセキュリティプロバイダに追加した BouncyCastleProvider をプロバイダとして使います。
署名アルゴリズムとしてSHA256 with RSAを選んでみます。

ContentSigner contentSigner = new JcaContentSignerBuilder("SHA256WithRSA").setProvider(bcProvider).build(keyPair.getPrivate());

ようやく実際の署名処理です。
X.509証明書を作成するために必要とした情報を持った certificateBuilder に、OutputStreamに署名する contentSigner を渡して署名します。

X509CertificateHolder certificateHolder = certificateBuilder.build(contentSigner);

すると X509Certificate を持つホルダークラスが返ってくるので、

X509Certificate selfSignedCertificate = new JcaX509CertificateConverter().getCertificate(certificateHolder);

とJCAを使ってホルダーから証明書を抽出してやれば、みんな大好き X509Certificate の出来上がりです。

まとめ

ということで、キーペアを作成して自己署名証明書を発行するところまででした。
あとは X509Certificate をBase64エンコードしてやればPEMとして扱うことができるはず。

以上です。

7
4
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
7
4