Skip to content

Commit c4e95b8

Browse files
committed
Merge branch 'ECA-12605-Support-Import-Debian-weak-keys-with-UpdatePublicKeyBlacklistCommand' into 'main'
Resolve ECA-12605 "Support import debian weak keys with updatepublickeyblacklistcommand" Closes ECA-12605 See merge request ejbca/ejbca!1778
2 parents b3cb8cb + 32877a4 commit c4e95b8

File tree

1 file changed

+101
-0
lines changed

1 file changed

+101
-0
lines changed

modules/ejbca-ejb-cli/src/org/ejbca/ui/cli/ca/UpdatePublicKeyBlacklistCommand.java

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,15 @@
1414
package org.ejbca.ui.cli.ca;
1515

1616
import java.io.File;
17+
import java.io.FileInputStream;
1718
import java.io.FileReader;
19+
import java.security.KeyFactory;
20+
import java.security.MessageDigest;
21+
import java.security.NoSuchAlgorithmException;
22+
import java.security.NoSuchProviderException;
1823
import java.security.PublicKey;
24+
import java.security.Security;
25+
import java.security.spec.InvalidKeySpecException;
1926
import java.util.Arrays;
2027
import java.util.HashSet;
2128
import java.util.List;
@@ -24,6 +31,17 @@
2431
import org.apache.commons.io.IOUtils;
2532
import org.apache.commons.lang.StringUtils;
2633
import 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;
2745
import org.cesecore.authorization.AuthorizationDeniedException;
2846
import org.cesecore.util.EjbRemoteHelper;
2947
import org.ejbca.core.ejb.ca.validation.BlacklistDoesntExistsException;
@@ -37,6 +55,7 @@
3755
import org.ejbca.ui.cli.infrastructure.parameter.enums.ParameterMode;
3856
import org.ejbca.ui.cli.infrastructure.parameter.enums.StandaloneMode;
3957

58+
//import com.google.common.io.Files;
4059
import com.keyfactor.util.CryptoProviderTools;
4160
import com.keyfactor.util.FileTools;
4261
import 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

Comments
 (0)