|
@@ -28,6 +28,7 @@ import password.pwm.config.option.CertificateMatchingMode;
|
|
import password.pwm.error.ErrorInformation;
|
|
import password.pwm.error.ErrorInformation;
|
|
import password.pwm.error.PwmError;
|
|
import password.pwm.error.PwmError;
|
|
import password.pwm.error.PwmException;
|
|
import password.pwm.error.PwmException;
|
|
|
|
+import password.pwm.error.PwmInternalException;
|
|
import password.pwm.error.PwmOperationalException;
|
|
import password.pwm.error.PwmOperationalException;
|
|
import password.pwm.error.PwmUnrecoverableException;
|
|
import password.pwm.error.PwmUnrecoverableException;
|
|
import password.pwm.http.HttpMethod;
|
|
import password.pwm.http.HttpMethod;
|
|
@@ -56,7 +57,6 @@ import java.security.GeneralSecurityException;
|
|
import java.security.KeyStore;
|
|
import java.security.KeyStore;
|
|
import java.security.KeyStoreException;
|
|
import java.security.KeyStoreException;
|
|
import java.security.NoSuchAlgorithmException;
|
|
import java.security.NoSuchAlgorithmException;
|
|
-import java.security.PrivateKey;
|
|
|
|
import java.security.SecureRandom;
|
|
import java.security.SecureRandom;
|
|
import java.security.cert.CertificateEncodingException;
|
|
import java.security.cert.CertificateEncodingException;
|
|
import java.security.cert.CertificateException;
|
|
import java.security.cert.CertificateException;
|
|
@@ -65,10 +65,8 @@ import java.security.cert.X509Certificate;
|
|
import java.util.ArrayList;
|
|
import java.util.ArrayList;
|
|
import java.util.Collection;
|
|
import java.util.Collection;
|
|
import java.util.Collections;
|
|
import java.util.Collections;
|
|
-import java.util.LinkedHashMap;
|
|
|
|
import java.util.LinkedHashSet;
|
|
import java.util.LinkedHashSet;
|
|
import java.util.List;
|
|
import java.util.List;
|
|
-import java.util.Map;
|
|
|
|
import java.util.Objects;
|
|
import java.util.Objects;
|
|
import java.util.Optional;
|
|
import java.util.Optional;
|
|
import java.util.Set;
|
|
import java.util.Set;
|
|
@@ -82,11 +80,27 @@ public class X509Utils
|
|
{
|
|
{
|
|
private static final PwmLogger LOGGER = PwmLogger.forClass( X509Utils.class );
|
|
private static final PwmLogger LOGGER = PwmLogger.forClass( X509Utils.class );
|
|
|
|
|
|
- private X509Utils()
|
|
|
|
|
|
+ public enum ReadCertificateFlag
|
|
|
|
+ {
|
|
|
|
+ ReadOnlyRootCA
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public enum DebugInfoFlag
|
|
{
|
|
{
|
|
|
|
+ IncludeCertificateDetail
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
+ enum KeyDebugInfoKey
|
|
|
|
+ {
|
|
|
|
+ algorithm,
|
|
|
|
+ format,
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private X509Utils()
|
|
|
|
+ {
|
|
|
|
+ }
|
|
|
|
+
|
|
public static List<X509Certificate> readRemoteCertificates(
|
|
public static List<X509Certificate> readRemoteCertificates(
|
|
final URI uri,
|
|
final URI uri,
|
|
final AppConfig appConfig
|
|
final AppConfig appConfig
|
|
@@ -269,33 +283,31 @@ public class X509Utils
|
|
}
|
|
}
|
|
|
|
|
|
public static String makeDetailText( final X509Certificate x509Certificate )
|
|
public static String makeDetailText( final X509Certificate x509Certificate )
|
|
- throws CertificateEncodingException, PwmUnrecoverableException
|
|
|
|
{
|
|
{
|
|
- return x509Certificate.toString()
|
|
|
|
- + "\nMD5: " + hash( x509Certificate, PwmHashAlgorithm.MD5 )
|
|
|
|
- + "\nSHA1: " + hash( x509Certificate, PwmHashAlgorithm.SHA1 )
|
|
|
|
- + "\nSHA2-256: " + hash( x509Certificate, PwmHashAlgorithm.SHA256 )
|
|
|
|
- + "\nSHA2-512: " + hash( x509Certificate, PwmHashAlgorithm.SHA512 )
|
|
|
|
- + "\n:IsRootCA: " + certIsRootCA( x509Certificate );
|
|
|
|
|
|
+ final StringBuilder sb = new StringBuilder();
|
|
|
|
+ X509CertInfo.makeDebugInfoMapImpl( x509Certificate ).forEach( ( key, value ) ->
|
|
|
|
+ {
|
|
|
|
+ sb.append( key );
|
|
|
|
+ sb.append( ": " );
|
|
|
|
+ sb.append( value );
|
|
|
|
+ sb.append( "\n" );
|
|
|
|
+ } );
|
|
|
|
+
|
|
|
|
+ sb.append( x509Certificate );
|
|
|
|
+ sb.append( "\n" );
|
|
|
|
+ return sb.toString();
|
|
}
|
|
}
|
|
|
|
|
|
public static String makeDebugTexts( final List<X509Certificate> x509Certificates )
|
|
public static String makeDebugTexts( final List<X509Certificate> x509Certificates )
|
|
{
|
|
{
|
|
- final StringBuilder sb = new StringBuilder();
|
|
|
|
- sb.append( "Certificates: " );
|
|
|
|
- for ( final X509Certificate x509Certificate : x509Certificates )
|
|
|
|
- {
|
|
|
|
- sb.append( '[' );
|
|
|
|
- sb.append( makeDebugText( x509Certificate ) );
|
|
|
|
- sb.append( ']' );
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
- return sb.toString();
|
|
|
|
|
|
+ return x509Certificates.stream()
|
|
|
|
+ .map( x509Certificate -> '[' + makeDebugText( x509Certificate ) + ']' )
|
|
|
|
+ .collect( Collectors.joining( "", "Certificates: ", "" ) );
|
|
}
|
|
}
|
|
|
|
|
|
public static String makeDebugText( final X509Certificate x509Certificate )
|
|
public static String makeDebugText( final X509Certificate x509Certificate )
|
|
{
|
|
{
|
|
- return "subject=" + x509Certificate.getSubjectDN().getName() + ", serial=" + x509Certificate.getSerialNumber();
|
|
|
|
|
|
+ return "subject=" + X509CertDataParser.readCertSubject( x509Certificate ) + ", serial=" + x509Certificate.getSerialNumber();
|
|
}
|
|
}
|
|
|
|
|
|
public static List<X509Certificate> certificatesFromBase64s( final Collection<String> b64certificates )
|
|
public static List<X509Certificate> certificatesFromBase64s( final Collection<String> b64certificates )
|
|
@@ -363,80 +375,6 @@ public class X509Utils
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- enum CertDebugInfoKey
|
|
|
|
- {
|
|
|
|
- subject,
|
|
|
|
- serial,
|
|
|
|
- issuer,
|
|
|
|
- issueDate,
|
|
|
|
- expireDate,
|
|
|
|
- md5Hash,
|
|
|
|
- sha1Hash,
|
|
|
|
- sha512Hash,
|
|
|
|
- detail,
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public enum ReadCertificateFlag
|
|
|
|
- {
|
|
|
|
- ReadOnlyRootCA
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public enum DebugInfoFlag
|
|
|
|
- {
|
|
|
|
- IncludeCertificateDetail
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public static List<Map<String, String>> makeDebugInfoMap( final List<X509Certificate> certificates, final DebugInfoFlag... flags )
|
|
|
|
- {
|
|
|
|
- final List<Map<String, String>> returnList = new ArrayList<>();
|
|
|
|
- if ( certificates != null )
|
|
|
|
- {
|
|
|
|
- for ( final X509Certificate cert : certificates )
|
|
|
|
- {
|
|
|
|
- returnList.add( makeDebugInfoMap( cert, flags ) );
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return returnList;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public static Map<String, String> makeDebugInfoMap( final X509Certificate cert, final DebugInfoFlag... flags )
|
|
|
|
- {
|
|
|
|
- final Map<String, String> returnMap = new LinkedHashMap<>();
|
|
|
|
- returnMap.put( CertDebugInfoKey.subject.toString(), cert.getSubjectDN().toString() );
|
|
|
|
- returnMap.put( CertDebugInfoKey.serial.toString(), X509Utils.hexSerial( cert ) );
|
|
|
|
- returnMap.put( CertDebugInfoKey.issuer.toString(), cert.getIssuerDN().toString() );
|
|
|
|
- returnMap.put( CertDebugInfoKey.issueDate.toString(), StringUtil.toIsoDate( cert.getNotBefore().toInstant() ) );
|
|
|
|
- returnMap.put( CertDebugInfoKey.expireDate.toString(), StringUtil.toIsoDate( cert.getNotAfter().toInstant() ) );
|
|
|
|
- try
|
|
|
|
- {
|
|
|
|
- returnMap.put( CertDebugInfoKey.md5Hash.toString(), hash( cert, PwmHashAlgorithm.MD5 ) );
|
|
|
|
- returnMap.put( CertDebugInfoKey.sha1Hash.toString(), hash( cert, PwmHashAlgorithm.SHA1 ) );
|
|
|
|
- returnMap.put( CertDebugInfoKey.sha512Hash.toString(), hash( cert, PwmHashAlgorithm.SHA512 ) );
|
|
|
|
- if ( JavaHelper.enumArrayContainsValue( flags, DebugInfoFlag.IncludeCertificateDetail ) )
|
|
|
|
- {
|
|
|
|
- returnMap.put( CertDebugInfoKey.detail.toString(), X509Utils.makeDetailText( cert ) );
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- catch ( final PwmUnrecoverableException | CertificateEncodingException e )
|
|
|
|
- {
|
|
|
|
- LOGGER.warn( () -> "error generating hash for certificate: " + e.getMessage() );
|
|
|
|
- }
|
|
|
|
- return returnMap;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- enum KeyDebugInfoKey
|
|
|
|
- {
|
|
|
|
- algorithm,
|
|
|
|
- format,
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public static Map<String, String> makeDebugInfoMap( final PrivateKey key )
|
|
|
|
- {
|
|
|
|
- final Map<String, String> returnMap = new LinkedHashMap<>();
|
|
|
|
- returnMap.put( KeyDebugInfoKey.algorithm.toString(), key.getAlgorithm() );
|
|
|
|
- returnMap.put( KeyDebugInfoKey.format.toString(), key.getFormat() );
|
|
|
|
- return returnMap;
|
|
|
|
- }
|
|
|
|
|
|
|
|
public static X509Certificate certificateFromBase64( final String b64encodedStr )
|
|
public static X509Certificate certificateFromBase64( final String b64encodedStr )
|
|
throws CertificateException, IOException
|
|
throws CertificateException, IOException
|
|
@@ -462,7 +400,7 @@ public class X509Utils
|
|
|
|
|
|
for ( final X509Certificate certificate : certificates )
|
|
for ( final X509Certificate certificate : certificates )
|
|
{
|
|
{
|
|
- if ( certIsRootCA( certificate ) )
|
|
|
|
|
|
+ if ( X509CertDataParser.certIsSigningKey( certificate ) )
|
|
{
|
|
{
|
|
returnList.add( certificate );
|
|
returnList.add( certificate );
|
|
}
|
|
}
|
|
@@ -476,21 +414,6 @@ public class X509Utils
|
|
return Optional.empty();
|
|
return Optional.empty();
|
|
}
|
|
}
|
|
|
|
|
|
- private static boolean certIsRootCA( final X509Certificate certificate )
|
|
|
|
- {
|
|
|
|
- final int keyCertSignBitPosition = 5;
|
|
|
|
- final boolean[] keyUsages = certificate.getKeyUsage();
|
|
|
|
- if ( keyUsages != null && keyUsages.length > keyCertSignBitPosition - 1 )
|
|
|
|
- {
|
|
|
|
- if ( keyUsages[keyCertSignBitPosition] )
|
|
|
|
- {
|
|
|
|
- return true;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
public static TrustManager[] getDefaultJavaTrustManager( final AppConfig appConfig )
|
|
public static TrustManager[] getDefaultJavaTrustManager( final AppConfig appConfig )
|
|
throws PwmUnrecoverableException
|
|
throws PwmUnrecoverableException
|
|
{
|
|
{
|
|
@@ -509,7 +432,6 @@ public class X509Utils
|
|
}
|
|
}
|
|
|
|
|
|
public static String hash( final X509Certificate certificate, final PwmHashAlgorithm pwmHashAlgorithm )
|
|
public static String hash( final X509Certificate certificate, final PwmHashAlgorithm pwmHashAlgorithm )
|
|
- throws PwmUnrecoverableException
|
|
|
|
{
|
|
{
|
|
try
|
|
try
|
|
{
|
|
{
|
|
@@ -517,7 +439,8 @@ public class X509Utils
|
|
}
|
|
}
|
|
catch ( final CertificateEncodingException e )
|
|
catch ( final CertificateEncodingException e )
|
|
{
|
|
{
|
|
- throw PwmUnrecoverableException.newException( PwmError.ERROR_INTERNAL, "unexpected error encoding certificate: " + e.getMessage() );
|
|
|
|
|
|
+ throw new PwmInternalException( new ErrorInformation( PwmError.ERROR_INTERNAL,
|
|
|
|
+ "unexpected error encoding certificate: " + e.getMessage() ) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -548,5 +471,4 @@ public class X509Utils
|
|
}
|
|
}
|
|
return Collections.unmodifiableSet( resultCertificates );
|
|
return Collections.unmodifiableSet( resultCertificates );
|
|
}
|
|
}
|
|
-
|
|
|
|
}
|
|
}
|