1414package org .ejbca .ui .cli .ca ;
1515
1616import java .io .File ;
17+ import java .io .FileInputStream ;
1718import java .io .FileReader ;
19+ import java .security .KeyFactory ;
20+ import java .security .MessageDigest ;
21+ import java .security .NoSuchAlgorithmException ;
22+ import java .security .NoSuchProviderException ;
1823import java .security .PublicKey ;
24+ import java .security .Security ;
25+ import java .security .spec .InvalidKeySpecException ;
1926import java .util .Arrays ;
2027import java .util .HashSet ;
2128import java .util .List ;
2431import org .apache .commons .io .IOUtils ;
2532import org .apache .commons .lang .StringUtils ;
2633import org .apache .log4j .Logger ;
34+ import org .bouncycastle .asn1 .ASN1Sequence ;
35+ import org .bouncycastle .asn1 .pkcs .RSAPrivateKey ;
36+ import org .bouncycastle .asn1 .sec .ECPrivateKey ;
37+ import org .bouncycastle .jcajce .provider .asymmetric .ec .BCECPrivateKey ;
38+ import org .bouncycastle .jce .ECNamedCurveTable ;
39+ import org .bouncycastle .jce .provider .BouncyCastleProvider ;
40+ import org .bouncycastle .jce .spec .ECNamedCurveParameterSpec ;
41+ import org .bouncycastle .jce .spec .ECPrivateKeySpec ;
42+ import org .bouncycastle .jce .spec .ECPublicKeySpec ;
43+ import org .bouncycastle .math .ec .ECPoint ;
44+ import org .bouncycastle .util .encoders .Hex ;
2745import org .cesecore .authorization .AuthorizationDeniedException ;
2846import org .cesecore .util .EjbRemoteHelper ;
2947import org .ejbca .core .ejb .ca .validation .BlacklistDoesntExistsException ;
3755import org .ejbca .ui .cli .infrastructure .parameter .enums .ParameterMode ;
3856import org .ejbca .ui .cli .infrastructure .parameter .enums .StandaloneMode ;
3957
58+ //import com.google.common.io.Files;
4059import com .keyfactor .util .CryptoProviderTools ;
4160import com .keyfactor .util .FileTools ;
4261import com .keyfactor .util .keys .KeyTools ;
@@ -60,6 +79,7 @@ public class UpdatePublicKeyBlacklistCommand extends BaseCaAdminCommand {
6079 public static final String COMMAND_GEN_SQL = "generatesql" ;
6180 public static final String UPDATE_MODE_FINGERPRINT = "fingerprint" ;
6281 public static final String UPDATE_MODE_DEBIAN_FINGERPRINT = "debianfingerprint" ;
82+ public static final String UPDATE_MODE_DEBIAN_KEY = "debiankey" ;
6383 public static final String CSV_SEPARATOR = "," ;
6484
6585 {
@@ -75,6 +95,13 @@ public class UpdatePublicKeyBlacklistCommand extends BaseCaAdminCommand {
7595 " as Debian weak key block lists, where each line" + System .lineSeparator () +
7696 " is the fingerprint of a weak Debian key." + System .lineSeparator () +
7797 " See https://wiki.debian.org/SSLkeys" + System .lineSeparator () +
98+ " debiankey - If the input files shall be treated as a" + System .lineSeparator () +
99+ " Debian weak key block lists, where each file" + System .lineSeparator () +
100+ " is the private key of a weak Debian key." + System .lineSeparator () +
101+ " See https://github.com/CVE-2008-0166/private_keys" + System .lineSeparator () +
102+ " Makes hashes of it" + System .lineSeparator () +
103+ " and stores the hashes in the database." + System .lineSeparator () +
104+
78105 "If not specified, the input files are treated as PEM-encoded public keys." ));
79106 registerParameter (new Parameter (DIRECTORY_KEY , "Public key directory" , MandatoryMode .MANDATORY , StandaloneMode .ALLOW , ParameterMode .ARGUMENT ,
80107 "Directory with block list data." ));
@@ -109,6 +136,7 @@ public CommandResult execute(ParameterContainer parameters) {
109136 final String importDirString = parameters .get (DIRECTORY_KEY );
110137 final boolean byFingerprint = UPDATE_MODE_FINGERPRINT .equals (parameters .get (UPDATE_MODE_KEY ));
111138 final boolean byDebianFingerprint = UPDATE_MODE_DEBIAN_FINGERPRINT .equals (parameters .get (UPDATE_MODE_KEY ));
139+ final boolean byDebianKey = UPDATE_MODE_DEBIAN_KEY .equals (parameters .get (UPDATE_MODE_KEY ));
112140 final boolean resumeOnError = parameters .containsKey (RESUME_ON_ERROR_KEY );
113141
114142 // Get all files in the directory to add/remove to/from public key blacklist.
@@ -177,6 +205,53 @@ public CommandResult execute(ParameterContainer parameters) {
177205 continue ;
178206 }
179207 state = addPublicKeyFingerprintToBlacklist (trimmedLine );
208+
209+ }
210+ } else if (byDebianKey ) {
211+ Security .addProvider (new BouncyCastleProvider ());
212+ //Read file to bytes
213+ log .info ("Read Debian private key fingerprints file " + path );
214+
215+ FileInputStream fileInputStream = new FileInputStream (file );
216+ byte [] byteArray = fileInputStream .readAllBytes ();
217+ fileInputStream .read (byteArray );
218+ fileInputStream .close ();
219+
220+ ASN1Sequence seq = ASN1Sequence .getInstance (byteArray );
221+ RSAPrivateKey rsaPrivateKey = null ;
222+ ECPrivateKey ecPrivateKey = null ;
223+
224+ try {
225+ rsaPrivateKey = RSAPrivateKey .getInstance (seq ) ;
226+ log .info ("Found RSA private: " + rsaPrivateKey .getEncoded ().length );
227+ }
228+ catch (Exception e ){
229+ ecPrivateKey = ECPrivateKey .getInstance (seq );
230+ log .info ("Found EC private: length " + ecPrivateKey .getEncoded ().length + ", algorithm OID '" + ecPrivateKey .getParametersObject ().toString () + "'." );
231+ }
232+
233+ String result = "" ;
234+ if (rsaPrivateKey != null ) {
235+ try {
236+ result = Hex .toHexString (MessageDigest .getInstance ("SHA-256" ).digest (rsaPrivateKey .getModulus ().toByteArray ()));
237+ state = addPublicKeyFingerprintToBlacklist (result );
238+ } catch (NoSuchAlgorithmException e ) {
239+ throw new RuntimeException ("Unable to create SHA-256 fingerprint. Is the algorithm supported on this system?" , e );
240+ }
241+ } else if (ecPrivateKey != null ) {
242+ try {
243+ result = getEcPublicKeyHash (ecPrivateKey );
244+ state = addPublicKeyFingerprintToBlacklist (result );
245+ } catch (NoSuchProviderException e ) {
246+ throw new RuntimeException ("Unable to create SHA-256 fingerprint. Crypto provider not found: " + e .getMessage (), e );
247+ } catch (NoSuchAlgorithmException e ) {
248+ throw new RuntimeException ("Unable to create SHA-256 fingerprint. Is the algorithm supported on this system?" , e );
249+ } catch (InvalidKeySpecException e ) {
250+ throw new RuntimeException ("Unable to create SHA-256 fingerprint. Key specification is invalid: " + e .getMessage (), e );
251+ }
252+ } else {
253+ log .error ("Found unsupported key type for import." );
254+ state = STATUS_READ_ERROR ;
180255 }
181256 } else {
182257 log .info ("Read public key file " + path );
@@ -434,6 +509,32 @@ private int removeFromBlacklist(final String type, final String value) throws Ex
434509 return result ;
435510 }
436511
512+ /**
513+ * Gets the SHA-256 hash over the public key derived by the private key.
514+ *
515+ * @param privateKey the private EC key.
516+ *
517+ * @return SHA-256 hash over the public key.
518+ *
519+ * @throws NoSuchAlgorithmException if the algorithm is not supported.
520+ * @throws NoSuchProviderException if the crypto provider is not available.
521+ * @throws InvalidKeySpecException if the key specification is invalid.
522+ */
523+ private String getEcPublicKeyHash (ECPrivateKey ecPrivateKey ) throws NoSuchAlgorithmException , NoSuchProviderException , InvalidKeySpecException {
524+ // Get the bouncy castle EC private key.
525+ final ECNamedCurveParameterSpec params = ECNamedCurveTable .getParameterSpec (ecPrivateKey .getParametersObject ().toString ());
526+ final ECPrivateKeySpec privSpec = new ECPrivateKeySpec (ecPrivateKey .getKey (), params );
527+ final KeyFactory factory = KeyFactory .getInstance ("ECDSA" , "BC" );
528+ final BCECPrivateKey privateKey = (BCECPrivateKey ) factory .generatePrivate (privSpec );
529+
530+ // Derive the public key by the private key and the key specification.
531+ final ECPoint point = params .getG ().multiply (privateKey .getD ());
532+ final ECPublicKeySpec pubSpec = new ECPublicKeySpec (point , params );
533+ final PublicKey publicKey = factory .generatePublic (pubSpec );
534+
535+ return Hex .toHexString (MessageDigest .getInstance ("SHA-256" ).digest (publicKey .getEncoded ()));
536+ }
537+
437538 /**
438539 * Logs the summary to STDOUT.
439540 *
0 commit comments