001/* 002 * acme4j - Java ACME client 003 * 004 * Copyright (C) 2015 Richard "Shred" Körber 005 * http://acme4j.shredzone.org 006 * 007 * Licensed under the Apache License, Version 2.0 (the "License"); 008 * you may not use this file except in compliance with the License. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 013 */ 014package org.shredzone.acme4j.util; 015 016import static org.assertj.core.api.Assertions.assertThat; 017 018import java.io.IOException; 019import java.io.StringReader; 020import java.io.StringWriter; 021import java.lang.reflect.Modifier; 022import java.security.KeyPair; 023import java.security.Security; 024import java.security.interfaces.ECPublicKey; 025import java.security.interfaces.RSAPublicKey; 026 027import org.bouncycastle.jce.provider.BouncyCastleProvider; 028import org.junit.jupiter.api.BeforeAll; 029import org.junit.jupiter.api.Test; 030 031/** 032 * Unit tests for {@link KeyPairUtils}. 033 */ 034public class KeyPairUtilsTest { 035 private static final int KEY_SIZE = 2048; 036 private static final String EC_CURVE = "secp256r1"; 037 038 @BeforeAll 039 public static void setup() { 040 Security.addProvider(new BouncyCastleProvider()); 041 } 042 043 /** 044 * Test that standard keypair generates a secure key pair. 045 */ 046 @Test 047 public void testCreateStandardKeyPair() { 048 var pair = KeyPairUtils.createKeyPair(); 049 assertThat(pair).isNotNull(); 050 assertThat(pair.getPublic()).isInstanceOf(ECPublicKey.class); 051 var pk = (ECPublicKey) pair.getPublic(); 052 assertThat(pk.getAlgorithm()).isEqualTo("ECDSA"); 053 assertThat(pk.getParams().getCurve().getField().getFieldSize()).isEqualTo(384); 054 } 055 056 /** 057 * Test that RSA keypairs of the correct size are generated. 058 */ 059 @Test 060 public void testCreateKeyPair() { 061 var pair = KeyPairUtils.createKeyPair(KEY_SIZE); 062 assertThat(pair).isNotNull(); 063 assertThat(pair.getPublic()).isInstanceOf(RSAPublicKey.class); 064 065 var pub = (RSAPublicKey) pair.getPublic(); 066 assertThat(pub.getModulus().bitLength()).isEqualTo(KEY_SIZE); 067 } 068 069 /** 070 * Test that reading and writing keypairs work correctly. 071 */ 072 @Test 073 public void testWriteAndRead() throws IOException { 074 // Generate a test keypair 075 var pair = KeyPairUtils.createKeyPair(KEY_SIZE); 076 077 // Write keypair to PEM 078 String pem; 079 try (var out = new StringWriter()) { 080 KeyPairUtils.writeKeyPair(pair, out); 081 pem = out.toString(); 082 } 083 084 // Make sure PEM file is properly formatted 085 assertThat(pem).matches( 086 "-----BEGIN RSA PRIVATE KEY-----[\\r\\n]+" 087 + "([a-zA-Z0-9/+=]+[\\r\\n]+)+" 088 + "-----END RSA PRIVATE KEY-----[\\r\\n]*"); 089 090 // Read keypair from PEM 091 KeyPair readPair; 092 try (var in = new StringReader(pem)) { 093 readPair = KeyPairUtils.readKeyPair(in); 094 } 095 096 // Verify that both keypairs are the same 097 assertThat(pair).isNotSameAs(readPair); 098 assertThat(pair.getPublic().getEncoded()).isEqualTo(readPair.getPublic().getEncoded()); 099 assertThat(pair.getPrivate().getEncoded()).isEqualTo(readPair.getPrivate().getEncoded()); 100 } 101 102 /** 103 * Test that ECDSA keypairs are generated. 104 */ 105 @Test 106 public void testCreateECCKeyPair() { 107 var pair = KeyPairUtils.createECKeyPair(EC_CURVE); 108 assertThat(pair).isNotNull(); 109 assertThat(pair.getPublic()).isInstanceOf(ECPublicKey.class); 110 } 111 112 /** 113 * Test that reading and writing ECDSA keypairs work correctly. 114 */ 115 @Test 116 public void testWriteAndReadEC() throws IOException { 117 // Generate a test keypair 118 var pair = KeyPairUtils.createECKeyPair(EC_CURVE); 119 120 // Write keypair to PEM 121 String pem; 122 try (var out = new StringWriter()) { 123 KeyPairUtils.writeKeyPair(pair, out); 124 pem = out.toString(); 125 } 126 127 // Make sure PEM file is properly formatted 128 assertThat(pem).matches( 129 "-----BEGIN EC PRIVATE KEY-----[\\r\\n]+" 130 + "([a-zA-Z0-9/+=]+[\\r\\n]+)+" 131 + "-----END EC PRIVATE KEY-----[\\r\\n]*"); 132 133 // Read keypair from PEM 134 KeyPair readPair; 135 try (var in = new StringReader(pem)) { 136 readPair = KeyPairUtils.readKeyPair(in); 137 } 138 139 // Verify that both keypairs are the same 140 assertThat(pair).isNotSameAs(readPair); 141 assertThat(pair.getPublic().getEncoded()).isEqualTo(readPair.getPublic().getEncoded()); 142 assertThat(pair.getPrivate().getEncoded()).isEqualTo(readPair.getPrivate().getEncoded()); 143 144 // Write Public Key 145 String publicPem; 146 try (var out = new StringWriter()) { 147 KeyPairUtils.writePublicKey(pair.getPublic(), out); 148 publicPem = out.toString(); 149 } 150 151 // Make sure PEM file is properly formatted 152 assertThat(publicPem).matches( 153 "-----BEGIN PUBLIC KEY-----[\\r\\n]+" 154 + "([a-zA-Z0-9/+=]+[\\r\\n]+)+" 155 + "-----END PUBLIC KEY-----[\\r\\n]*"); 156 } 157 158 /** 159 * Test that constructor is private. 160 */ 161 @Test 162 public void testPrivateConstructor() throws Exception { 163 var constructor = KeyPairUtils.class.getDeclaredConstructor(); 164 assertThat(Modifier.isPrivate(constructor.getModifiers())).isTrue(); 165 constructor.setAccessible(true); 166 constructor.newInstance(); 167 } 168 169}