You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by se...@apache.org on 2017/04/07 12:36:31 UTC

cxf git commit: Propagating X509 cert hash to OAuth2 providers, minor updates to the JOSE code

Repository: cxf
Updated Branches:
  refs/heads/master df9af7a3e -> 0eef86f37


Propagating X509 cert hash to OAuth2 providers, minor updates to the JOSE code


Project: http://git-wip-us.apache.org/repos/asf/cxf/repo
Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/0eef86f3
Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/0eef86f3
Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/0eef86f3

Branch: refs/heads/master
Commit: 0eef86f37288f71fd96506fb2ac7fa27169d1e43
Parents: df9af7a
Author: Sergey Beryozkin <sb...@gmail.com>
Authored: Fri Apr 7 13:36:16 2017 +0100
Committer: Sergey Beryozkin <sb...@gmail.com>
Committed: Fri Apr 7 13:36:16 2017 +0100

----------------------------------------------------------------------
 .../rs/security/jose/common/JoseConstants.java  | 10 +++
 .../jose/common/KeyManagementUtils.java         |  5 +-
 .../cxf/rs/security/jose/jwe/JweUtils.java      | 34 +++++++++-
 .../cxf/rs/security/jose/jws/JwsUtils.java      | 31 ++++++++-
 .../oauth2/services/AbstractTokenService.java   | 69 ++++----------------
 .../rs/security/oauth2/utils/OAuthUtils.java    | 67 +++++++++++++++++++
 6 files changed, 151 insertions(+), 65 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cxf/blob/0eef86f3/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/JoseConstants.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/JoseConstants.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/JoseConstants.java
index 6abbd5f..bcf9d79 100644
--- a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/JoseConstants.java
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/JoseConstants.java
@@ -173,6 +173,11 @@ public final class JoseConstants {
      * Include the X.509 certificate SHA-1 digest for signature in the "x5t" header.
      */
     public static final String RSSEC_SIGNATURE_INCLUDE_CERT_SHA1 = "rs.security.signature.include.cert.sha1";
+    
+    /**
+     * Include the X.509 certificate SHA-256 digest for signature in the "x5t#S256" header.
+     */
+    public static final String RSSEC_SIGNATURE_INCLUDE_CERT_SHA256 = "rs.security.signature.include.cert.sha1";
 
     //
     // JWE specific Configuration
@@ -236,6 +241,11 @@ public final class JoseConstants {
      * Include the X.509 certificate SHA-1 digest for encryption in the "x5t" header.
      */
     public static final String RSSEC_ENCRYPTION_INCLUDE_CERT_SHA1 = "rs.security.encryption.include.cert.sha1";
+    
+    /**
+     * Include the X.509 certificate SHA-246 digest for encryption in the "x5t#S256" header.
+     */
+    public static final String RSSEC_ENCRYPTION_INCLUDE_CERT_SHA256 = "rs.security.encryption.include.cert.sha256";
 
     //
     // JWT specific configuration

http://git-wip-us.apache.org/repos/asf/cxf/blob/0eef86f3/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/KeyManagementUtils.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/KeyManagementUtils.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/KeyManagementUtils.java
index f599e5b..63c0b08 100644
--- a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/KeyManagementUtils.java
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/KeyManagementUtils.java
@@ -69,13 +69,12 @@ public final class KeyManagementUtils {
         return encodeX509CertificateChain(chain);
     }
 
-    public static String loadDigestAndEncodeX509Certificate(Message m, Properties props) {
+    public static String loadDigestAndEncodeX509Certificate(Message m, Properties props, String digestAlgo) {
         X509Certificate[] certs = loadX509CertificateOrChain(m, props);
         if (certs != null && certs.length > 0) {
             try {
                 byte[] digest =
-                    MessageDigestUtils.createDigest(certs[0].getEncoded(),
-                                                MessageDigestUtils.ALGO_SHA_1);
+                    MessageDigestUtils.createDigest(certs[0].getEncoded(), digestAlgo);
                 return Base64UrlUtility.encode(digest);
             } catch (NoSuchAlgorithmException ex) {
                 LOG.log(Level.FINE, "Error creating digest", ex);

http://git-wip-us.apache.org/repos/asf/cxf/blob/0eef86f3/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java
index 613fc77..3d851f8 100644
--- a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java
@@ -347,6 +347,8 @@ public final class JweUtils {
                 m, JoseConstants.RSSEC_ENCRYPTION_INCLUDE_CERT, false);
         boolean includeCertSha1 = headers != null && MessageUtils.getContextualBoolean(
                 m, JoseConstants.RSSEC_ENCRYPTION_INCLUDE_CERT_SHA1, false);
+        boolean includeCertSha256 = !includeCertSha1 && headers != null && MessageUtils.getContextualBoolean(
+                m, JoseConstants.RSSEC_ENCRYPTION_INCLUDE_CERT_SHA256, false);
 
         KeyEncryptionProvider keyEncryptionProvider = null;
         KeyAlgorithm keyAlgo = getKeyEncryptionAlgorithm(m, props, null, null);
@@ -377,10 +379,17 @@ public final class JweUtils {
                     JwkUtils.includeCertChain(jwk, headers, keyAlgo.getJwaName());
                 }
                 if (includeCertSha1) {
-                    String digest = KeyManagementUtils.loadDigestAndEncodeX509Certificate(m, props);
+                    String digest = KeyManagementUtils.loadDigestAndEncodeX509Certificate(m, 
+                                        props, MessageDigestUtils.ALGO_SHA_1);
                     if (digest != null) {
                         headers.setX509Thumbprint(digest);
                     }
+                } else if (includeCertSha256) {
+                    String digest = KeyManagementUtils.loadDigestAndEncodeX509Certificate(m, 
+                                        props, MessageDigestUtils.ALGO_SHA_256);
+                    if (digest != null) {
+                        headers.setX509ThumbprintSHA256(digest);
+                    }
                 }
                 if (includePublicKey) {
                     JwkUtils.includePublicKey(jwk, headers, keyAlgo.getJwaName());
@@ -398,10 +407,17 @@ public final class JweUtils {
                 headers.setX509Chain(KeyManagementUtils.loadAndEncodeX509CertificateOrChain(m, props));
             }
             if (includeCertSha1) {
-                String digest = KeyManagementUtils.loadDigestAndEncodeX509Certificate(m, props);
+                String digest = KeyManagementUtils.loadDigestAndEncodeX509Certificate(m, 
+                                    props, MessageDigestUtils.ALGO_SHA_1);
                 if (digest != null) {
                     headers.setX509Thumbprint(digest);
                 }
+            } else if (includeCertSha256) {
+                String digest = KeyManagementUtils.loadDigestAndEncodeX509Certificate(m, 
+                                    props, MessageDigestUtils.ALGO_SHA_256);
+                if (digest != null) {
+                    headers.setX509ThumbprintSHA256(digest);
+                }
             }
         }
 
@@ -460,6 +476,20 @@ public final class JweUtils {
                 contentAlgo = inHeaders.getContentEncryptionAlgorithm();
                 keyDecryptionProvider = getPrivateKeyDecryptionProvider(privateKey, keyAlgo);
             }
+        } else if (inHeaders != null && inHeaders.getHeader(JoseConstants.HEADER_X509_THUMBPRINT_SHA256) != null) {
+            X509Certificate foundCert =
+                KeyManagementUtils.getCertificateFromThumbprint(inHeaders.getX509ThumbprintSHA256(),
+                                                                MessageDigestUtils.ALGO_SHA_256,
+                                                                m, props);
+            if (foundCert != null) {
+                PrivateKey privateKey =
+                    KeyManagementUtils.loadPrivateKey(m, props, foundCert, KeyOperation.DECRYPT);
+                if (keyAlgo == null) {
+                    keyAlgo = getDefaultPrivateKeyAlgorithm(privateKey);
+                }
+                contentAlgo = inHeaders.getContentEncryptionAlgorithm();
+                keyDecryptionProvider = getPrivateKeyDecryptionProvider(privateKey, keyAlgo);
+            }
         } else {
             if (JoseConstants.HEADER_JSON_WEB_KEY.equals(props.get(JoseConstants.RSSEC_KEY_STORE_TYPE))) {
                 JsonWebKey jwk = JwkUtils.loadJsonWebKey(m, props, KeyOperation.DECRYPT);

http://git-wip-us.apache.org/repos/asf/cxf/blob/0eef86f3/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsUtils.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsUtils.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsUtils.java
index 25f12ba..cd5a008 100644
--- a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsUtils.java
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsUtils.java
@@ -342,6 +342,8 @@ public final class JwsUtils {
                 m, JoseConstants.RSSEC_SIGNATURE_INCLUDE_CERT, false);
         boolean includeCertSha1 = headers != null && MessageUtils.getContextualBoolean(
                 m, JoseConstants.RSSEC_SIGNATURE_INCLUDE_CERT_SHA1, false);
+        boolean includeCertSha256 = !includeCertSha1 && headers != null && MessageUtils.getContextualBoolean(
+                                  m, JoseConstants.RSSEC_SIGNATURE_INCLUDE_CERT_SHA256, false);
         boolean includeKeyId = headers != null && MessageUtils.getContextualBoolean(
                 m, JoseConstants.RSSEC_SIGNATURE_INCLUDE_KEY_ID, false);
 
@@ -361,10 +363,17 @@ public final class JwsUtils {
                     JwkUtils.includeCertChain(jwk, headers, signatureAlgo.getJwaName());
                 }
                 if (includeCertSha1) {
-                    String digest = KeyManagementUtils.loadDigestAndEncodeX509Certificate(m, props);
+                    String digest = KeyManagementUtils.loadDigestAndEncodeX509Certificate(m, 
+                                        props, MessageDigestUtils.ALGO_SHA_1);
                     if (digest != null) {
                         headers.setX509Thumbprint(digest);
                     }
+                } else if (includeCertSha256) {
+                    String digest = KeyManagementUtils.loadDigestAndEncodeX509Certificate(m, 
+                                        props, MessageDigestUtils.ALGO_SHA_256);
+                    if (digest != null) {
+                        headers.setX509ThumbprintSHA256(digest);
+                    }
                 }
                 if (includePublicKey) {
                     JwkUtils.includePublicKey(jwk, headers, signatureAlgo.getJwaName());
@@ -388,11 +397,18 @@ public final class JwsUtils {
                     headers.setX509Chain(KeyManagementUtils.loadAndEncodeX509CertificateOrChain(m, props));
                 }
                 if (includeCertSha1) {
-                    String digest = KeyManagementUtils.loadDigestAndEncodeX509Certificate(m, props);
+                    String digest = KeyManagementUtils.loadDigestAndEncodeX509Certificate(m, 
+                                        props, MessageDigestUtils.ALGO_SHA_1);
                     if (digest != null) {
                         headers.setX509Thumbprint(digest);
                     }
-                }
+                } else if (includeCertSha256) {
+                    String digest = KeyManagementUtils.loadDigestAndEncodeX509Certificate(m, 
+                                        props, MessageDigestUtils.ALGO_SHA_256);
+                    if (digest != null) {
+                        headers.setX509ThumbprintSHA256(digest);
+                    }
+                }  
                 if (includeKeyId && props.containsKey(JoseConstants.RSSEC_KEY_STORE_ALIAS)) {
                     headers.setKeyId(props.getProperty(JoseConstants.RSSEC_KEY_STORE_ALIAS));
                 }
@@ -440,6 +456,15 @@ public final class JwsUtils {
                     return getPublicKeySignatureVerifier(foundCert,
                                                          inHeaders.getSignatureAlgorithm());
                 }
+            } else if (inHeaders.getHeader(JoseConstants.HEADER_X509_THUMBPRINT_SHA256) != null) {
+                X509Certificate foundCert =
+                    KeyManagementUtils.getCertificateFromThumbprint(inHeaders.getX509ThumbprintSHA256(),
+                                                                    MessageDigestUtils.ALGO_SHA_256,
+                                                                    m, props);
+                if (foundCert != null) {
+                    return getPublicKeySignatureVerifier(foundCert,
+                                                         inHeaders.getSignatureAlgorithm());
+                }
             }
         }
 

http://git-wip-us.apache.org/repos/asf/cxf/blob/0eef86f3/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AbstractTokenService.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AbstractTokenService.java b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AbstractTokenService.java
index 5992d04..826e86d 100644
--- a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AbstractTokenService.java
+++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AbstractTokenService.java
@@ -20,19 +20,15 @@
 package org.apache.cxf.rs.security.oauth2.services;
 
 import java.security.Principal;
-import java.security.cert.Certificate;
 import java.security.cert.X509Certificate;
-import java.util.Arrays;
 import java.util.List;
 
-import javax.security.auth.x500.X500Principal;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.ResponseBuilder;
 import javax.ws.rs.core.SecurityContext;
 
-import org.apache.cxf.common.util.Base64Utility;
 import org.apache.cxf.common.util.StringUtils;
 import org.apache.cxf.jaxrs.utils.ExceptionUtils;
 import org.apache.cxf.jaxrs.utils.JAXRSUtils;
@@ -43,6 +39,7 @@ import org.apache.cxf.rs.security.oauth2.provider.ClientSecretVerifier;
 import org.apache.cxf.rs.security.oauth2.provider.OAuthServiceException;
 import org.apache.cxf.rs.security.oauth2.utils.AuthorizationUtils;
 import org.apache.cxf.rs.security.oauth2.utils.OAuthConstants;
+import org.apache.cxf.rs.security.oauth2.utils.OAuthUtils;
 import org.apache.cxf.security.transport.TLSSessionInfo;
 
 public class AbstractTokenService extends AbstractOAuthService {
@@ -65,7 +62,7 @@ public class AbstractTokenService extends AbstractOAuthService {
                 String clientSecret = params.getFirst(OAuthConstants.CLIENT_SECRET);
                 if (clientSecret != null) {
                     client = getAndValidateClientFromIdAndSecret(clientId, clientSecret, params);
-                } else if (isMutualTls(sc, getTlsSessionInfo())) {
+                } else if (OAuthUtils.isMutualTls(sc, getTlsSessionInfo())) {
                     client = getClient(clientId, params);
                     checkCertificateBinding(client, getTlsSessionInfo());
                 }
@@ -154,21 +151,23 @@ public class AbstractTokenService extends AbstractOAuthService {
             LOG.warning("Client \"" + client.getClientId() + "\" can not be bound to the TLS cerificate");
             reportInvalidClient();
         }
+        X509Certificate cert = OAuthUtils.getRootTLSCertificate(tlsSessionInfo);
         
         if (subjectDn != null 
-            && !subjectDn.equals(getSubjectDnFromTLSCertificates(tlsSessionInfo))) {
+            && !subjectDn.equals(OAuthUtils.getSubjectDnFromTLSCertificates(cert))) {
             LOG.warning("Client \"" + client.getClientId() + "\" can not be bound to the TLS cerificate");
             reportInvalidClient();
         }
         String issuerDn = client.getProperties().get(OAuthConstants.TLS_CLIENT_AUTH_ISSUER_DN);
         if (issuerDn != null 
-            && !issuerDn.equals(getIssuerDnFromTLSCertificates(tlsSessionInfo))) {
+            && !issuerDn.equals(OAuthUtils.getIssuerDnFromTLSCertificates(cert))) {
             LOG.warning("Client \"" + client.getClientId() + "\" can not be bound to the TLS cerificate");
             reportInvalidClient();
         }
         if (!client.getApplicationCertificates().isEmpty()) {
             compareTlsCertificates(tlsSessionInfo, client.getApplicationCertificates());
         }
+        OAuthUtils.setCertificateThumbprintConfirmation(getMessageContext(), cert);
     }
 
     private TLSSessionInfo getTlsSessionInfo() {
@@ -181,71 +180,27 @@ public class AbstractTokenService extends AbstractOAuthService {
                                                   TLSSessionInfo tlsSessionInfo,
                                                   MultivaluedMap<String, String> params) {
         Client client = null;
-        if (isMutualTls(sc, tlsSessionInfo)) {
-            String subjectDn = getSubjectDnFromTLSCertificates(tlsSessionInfo);
+        if (OAuthUtils.isMutualTls(sc, tlsSessionInfo)) {
+            X509Certificate cert = OAuthUtils.getRootTLSCertificate(tlsSessionInfo);
+            String subjectDn = OAuthUtils.getSubjectDnFromTLSCertificates(cert);
             if (!StringUtils.isEmpty(subjectDn)) {
                 client = getClient(subjectDn, params);
                 // The certificates must be registered with the client and match TLS certificates
                 // in case of the binding where Client's clientId is a subject distinguished name
                 compareTlsCertificates(tlsSessionInfo, client.getApplicationCertificates());
+                OAuthUtils.setCertificateThumbprintConfirmation(getMessageContext(), cert);
             }
         }
         return client;
     }
-    protected boolean isMutualTls(SecurityContext sc, TLSSessionInfo tlsSessionInfo) {
-        // Pure 2-way TLS authentication
-        return tlsSessionInfo != null && StringUtils.isEmpty(sc.getAuthenticationScheme());
-    }
-
-    protected String getSubjectDnFromTLSCertificates(TLSSessionInfo tlsInfo) {
-        X509Certificate cert = getRootTLSCertificate(tlsInfo);
-        if (cert != null) {
-            X500Principal x509Principal = cert.getSubjectX500Principal();
-            return x509Principal.getName();
-        }
-        return null;
-    }
-    
-    protected String getIssuerDnFromTLSCertificates(TLSSessionInfo tlsInfo) {
-        X509Certificate cert = getRootTLSCertificate(tlsInfo);
-        if (cert != null) {
-            X500Principal x509Principal = cert.getIssuerX500Principal();
-            return x509Principal.getName();
-        }
-        return null;
-    }
     
-    protected X509Certificate getRootTLSCertificate(TLSSessionInfo tlsInfo) {
-        Certificate[] clientCerts = tlsInfo.getPeerCertificates();
-        if (clientCerts != null && clientCerts.length > 0) {
-            return (X509Certificate)clientCerts[0];
-        }
-        return null;
-    }
-
     protected void compareTlsCertificates(TLSSessionInfo tlsInfo,
                                           List<String> base64EncodedCerts) {
-        Certificate[] clientCerts = tlsInfo.getPeerCertificates();
-        if (clientCerts.length == base64EncodedCerts.size()) {
-            try {
-                for (int i = 0; i < clientCerts.length; i++) {
-                    X509Certificate x509Cert = (X509Certificate)clientCerts[i];
-                    byte[] encodedKey = x509Cert.getEncoded();
-                    byte[] clientKey = Base64Utility.decode(base64EncodedCerts.get(i));
-                    if (!Arrays.equals(encodedKey, clientKey)) {
-                        reportInvalidClient();
-                    }
-                }
-                return;
-            } catch (Exception ex) {
-                // throw exception later
-            }
+        if (!OAuthUtils.compareTlsCertificates(tlsInfo, base64EncodedCerts)) {
+            reportInvalidClient();    
         }
-        reportInvalidClient();
     }
 
-
-
     protected Response handleException(OAuthServiceException ex, String error) {
         OAuthError customError = ex.getError();
         if (writeCustomErrors && customError != null) {

http://git-wip-us.apache.org/repos/asf/cxf/blob/0eef86f3/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/OAuthUtils.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/OAuthUtils.java b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/OAuthUtils.java
index 743147e..c742e58 100644
--- a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/OAuthUtils.java
+++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/OAuthUtils.java
@@ -20,7 +20,10 @@ package org.apache.cxf.rs.security.oauth2.utils;
 
 import java.lang.reflect.Method;
 import java.security.Principal;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.LinkedList;
@@ -28,9 +31,12 @@ import java.util.List;
 import java.util.Properties;
 import java.util.Set;
 
+import javax.security.auth.x500.X500Principal;
 import javax.servlet.http.HttpSession;
 import javax.ws.rs.core.MultivaluedMap;
 
+import org.apache.cxf.common.util.Base64UrlUtility;
+import org.apache.cxf.common.util.Base64Utility;
 import org.apache.cxf.common.util.StringUtils;
 import org.apache.cxf.jaxrs.ext.MessageContext;
 import org.apache.cxf.jaxrs.impl.MetadataMap;
@@ -55,8 +61,10 @@ import org.apache.cxf.rs.security.oauth2.common.ServerAccessToken;
 import org.apache.cxf.rs.security.oauth2.common.UserSubject;
 import org.apache.cxf.rs.security.oauth2.provider.OAuthServiceException;
 import org.apache.cxf.rt.security.crypto.CryptoUtils;
+import org.apache.cxf.rt.security.crypto.MessageDigestUtils;
 import org.apache.cxf.security.LoginSecurityContext;
 import org.apache.cxf.security.SecurityContext;
+import org.apache.cxf.security.transport.TLSSessionInfo;
 
 /**
  * Various utility methods
@@ -66,6 +74,65 @@ public final class OAuthUtils {
     private OAuthUtils() {
     }
 
+
+    public static void setCertificateThumbprintConfirmation(MessageContext mc, X509Certificate cert) {
+        try {
+            byte[] thumbprint = 
+                MessageDigestUtils.createDigest(cert.getEncoded(), MessageDigestUtils.ALGO_SHA_256);
+            String encodedThumbprint = Base64UrlUtility.encode(thumbprint);
+            mc.put("x5t#S256", encodedThumbprint);
+        } catch (Exception ex) {
+            throw new OAuthServiceException(ex);
+        }
+    }
+    
+
+    public static boolean compareTlsCertificates(TLSSessionInfo tlsInfo,
+                                          List<String> base64EncodedCerts) {
+        Certificate[] clientCerts = tlsInfo.getPeerCertificates();
+        if (clientCerts.length == base64EncodedCerts.size()) {
+            try {
+                for (int i = 0; i < clientCerts.length; i++) {
+                    X509Certificate x509Cert = (X509Certificate)clientCerts[i];
+                    byte[] encodedKey = x509Cert.getEncoded();
+                    byte[] clientKey = Base64Utility.decode(base64EncodedCerts.get(i));
+                    if (!Arrays.equals(encodedKey, clientKey)) {
+                        return false;
+                    }
+                }
+                return true;
+            } catch (Exception ex) {
+                // throw exception later
+            }
+        }
+        return false;
+    }
+    
+    public static boolean isMutualTls(javax.ws.rs.core.SecurityContext sc, TLSSessionInfo tlsSessionInfo) {
+        // Pure 2-way TLS authentication
+        return tlsSessionInfo != null 
+            && StringUtils.isEmpty(sc.getAuthenticationScheme())
+            && getRootTLSCertificate(tlsSessionInfo) != null;
+    }
+    
+    public static String getSubjectDnFromTLSCertificates(X509Certificate cert) {
+        X500Principal x509Principal = cert.getSubjectX500Principal();
+        return x509Principal.getName();
+    }
+    
+    public static String getIssuerDnFromTLSCertificates(X509Certificate cert) {
+        X500Principal x509Principal = cert.getIssuerX500Principal();
+        return x509Principal.getName();
+    }
+    
+    public static X509Certificate getRootTLSCertificate(TLSSessionInfo tlsInfo) {
+        Certificate[] clientCerts = tlsInfo.getPeerCertificates();
+        if (clientCerts != null && clientCerts.length > 0) {
+            return (X509Certificate)clientCerts[0];
+        }
+        return null;
+    }
+    
     public static void injectContextIntoOAuthProvider(MessageContext context, Object provider) {
         Method dataProviderContextMethod = null;
         try {