in sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/AbstractPEMResourceKeyPairParser.java [78:171]
public Collection<KeyPair> extractKeyPairs(
SessionContext session, NamedResource resourceKey,
String beginMarker, String endMarker,
FilePasswordProvider passwordProvider,
List<String> lines, Map<String, String> headers)
throws IOException, GeneralSecurityException {
if (GenericUtils.isEmpty(lines)) {
return Collections.emptyList();
}
Boolean encrypted = null;
byte[] initVector = null;
String algInfo = null;
int dataStartIndex = -1;
boolean hdrsAvailable = MapEntryUtils.isNotEmpty(headers);
for (int index = 0; index < lines.size(); index++) {
String line = GenericUtils.trimToEmpty(lines.get(index));
if (GenericUtils.isEmpty(line)) {
continue;
}
// check if header line - if not, assume data lines follow
int headerPos = line.indexOf(':');
if (headerPos < 0) {
dataStartIndex = index;
break;
}
String hdrName = line.substring(0, headerPos).trim();
String hdrValue = line.substring(headerPos + 1).trim();
if (!hdrsAvailable) {
Map<String, String> accHeaders = MapEntryUtils.isEmpty(headers)
? new TreeMap<>(String.CASE_INSENSITIVE_ORDER)
: headers;
accHeaders.put(hdrName, hdrValue);
}
if (hdrName.equalsIgnoreCase("Proc-Type")) {
if (encrypted != null) {
throw new StreamCorruptedException("Multiple encryption indicators in " + resourceKey);
}
hdrValue = hdrValue.toUpperCase();
encrypted = Boolean.valueOf(line.contains("ENCRYPTED"));
} else if (hdrName.equalsIgnoreCase("DEK-Info")) {
if ((initVector != null) || (algInfo != null)) {
throw new StreamCorruptedException("Multiple encryption settings in " + resourceKey);
}
int infoPos = hdrValue.indexOf(',');
if (infoPos < 0) {
throw new StreamCorruptedException(
resourceKey + ": Missing encryption data values separator in line '" + line + "'");
}
algInfo = hdrValue.substring(0, infoPos).trim();
String algInitVector = hdrValue.substring(infoPos + 1).trim();
initVector = BufferUtils.decodeHex(BufferUtils.EMPTY_HEX_SEPARATOR, algInitVector);
}
}
if (dataStartIndex < 0) {
throw new StreamCorruptedException("No data lines (only headers or empty) found in " + resourceKey);
}
List<String> dataLines = lines.subList(dataStartIndex, lines.size());
if ((encrypted != null) || (algInfo != null) || (initVector != null)) {
if (passwordProvider == null) {
throw new CredentialException("Missing password provider for encrypted resource=" + resourceKey);
}
byte[] encryptedData = KeyPairResourceParser.extractDataBytes(dataLines);
String algorithm = algInfo;
byte[] iv = initVector;
Collection<KeyPair> keys = passwordProvider.decode(session, resourceKey, password -> {
PrivateKeyEncryptionContext encContext = new PrivateKeyEncryptionContext(algorithm);
encContext.setPassword(password);
encContext.setInitVector(iv);
byte[] decodedData = GenericUtils.EMPTY_BYTE_ARRAY;
try {
decodedData = applyPrivateKeyCipher(encryptedData, encContext, false);
try (InputStream bais = new ByteArrayInputStream(decodedData)) {
return extractKeyPairs(session, resourceKey, beginMarker, endMarker, passwordProvider, bais, headers);
}
} finally {
Arrays.fill(decodedData, (byte) 0);
}
});
return keys == null ? Collections.emptyList() : keys;
}
return super.extractKeyPairs(session, resourceKey, beginMarker, endMarker, passwordProvider, dataLines, headers);
}