Commit 910dc255 authored by Guus der Kinderen's avatar Guus der Kinderen

OF-1100: id-on-dnsSRV otherName and URI could also have XMPP id

This commit adds support for the id-on-dnsSRV otherName, as well as
the UniformResourceIdentifier generalName, which both could also be
used for XMPP.
parent c9850548
...@@ -18,19 +18,36 @@ import org.slf4j.Logger; ...@@ -18,19 +18,36 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
* Certificate identity mapping that uses SubjectAlternativeName as the identity credentials. This implementation * Certificate identity mapping that uses SubjectAlternativeName as the identity credentials.
* combines subjectAltName entries of type otherName with an ASN.1 Object Identifier of "id-on-xmppAddr" with entries * This implementation returns all subjectAltName entries that are a:
* of type DNS. * <ul>
* <li>GeneralName of type otherName with the "id-on-xmppAddr" Object Identifier</li>
* <li>GeneralName of type otherName with the "id-on-dnsSRV" Object Identifier</li>
* <li>GeneralName of type DNSName</li>
* <li>GeneralName of type UniformResourceIdentifier</li>
* </ul>
* *
* @author Victor Hong * @author Victor Hong
* * @author Guus der Kinderen, guus@goodbytes.nl
*/ */
public class SANCertificateIdentityMapping implements CertificateIdentityMapping { public class SANCertificateIdentityMapping implements CertificateIdentityMapping {
private static final Logger Log = LoggerFactory.getLogger(SANCertificateIdentityMapping.class); private static final Logger Log = LoggerFactory.getLogger(SANCertificateIdentityMapping.class);
private static final String OTHERNAME_XMPP_OID = "1.3.6.1.5.5.7.8.5"; /**
* id-on-xmppAddr Object Identifier.
*
* @see <a href="http://tools.ietf.org/html/rfc6120>RFC 6120</a>
*/
public static final String OTHERNAME_XMPP_OID = "1.3.6.1.5.5.7.8.5";
/**
* id-on-dnsSRV Object Identifier.
*
* @see <a href="https://www.ietf.org/rfc/rfc4985.txt">RFC 4985</a>
*/
public static final String OTHERNAME_SRV_OID = "1.3.6.1.5.5.7.8.7";
/** /**
* Returns the JID representation of an XMPP entity contained as a SubjectAltName extension * Returns the JID representation of an XMPP entity contained as a SubjectAltName extension
* in the certificate. If none was found then return an empty list. * in the certificate. If none was found then return an empty list.
...@@ -54,15 +71,19 @@ public class SANCertificateIdentityMapping implements CertificateIdentityMapping ...@@ -54,15 +71,19 @@ public class SANCertificateIdentityMapping implements CertificateIdentityMapping
final String result; final String result;
switch ( type ) { switch ( type ) {
case 0: case 0:
// OtherName: search for "id-on-xmppAddr" // OtherName: search for "id-on-xmppAddr" or 'sRVName'
result = parseOtherName( (byte[]) value ); result = parseOtherName( (byte[]) value );
break; break;
case 2: case 2:
// DNS // DNS
result = (String) value; result = (String) value;
break; break;
case 6:
// URI
result = (String) value;
break;
default: default:
// Other types are not applicable for XMPP, so silently ignore them // Not applicable to XMPP, so silently ignore them
result = null; result = null;
break; break;
} }
...@@ -100,7 +121,7 @@ public class SANCertificateIdentityMapping implements CertificateIdentityMapping ...@@ -100,7 +121,7 @@ public class SANCertificateIdentityMapping implements CertificateIdentityMapping
try (ASN1InputStream decoder = new ASN1InputStream(item)) { try (ASN1InputStream decoder = new ASN1InputStream(item)) {
// Value is encoded using ASN.1 so decode it to get the server's identity // Value is encoded using ASN.1 so decode it to get the server's identity
Object object = decoder.readObject(); Object object = decoder.readObject();
ASN1Sequence otherNameSeq = null; ASN1Sequence otherNameSeq;
if (object != null && object instanceof ASN1Sequence) { if (object != null && object instanceof ASN1Sequence) {
otherNameSeq = (ASN1Sequence) object; otherNameSeq = (ASN1Sequence) object;
} else { } else {
...@@ -110,33 +131,17 @@ public class SANCertificateIdentityMapping implements CertificateIdentityMapping ...@@ -110,33 +131,17 @@ public class SANCertificateIdentityMapping implements CertificateIdentityMapping
ASN1ObjectIdentifier objectId = (ASN1ObjectIdentifier) otherNameSeq.getObjectAt(0); ASN1ObjectIdentifier objectId = (ASN1ObjectIdentifier) otherNameSeq.getObjectAt(0);
Log.debug("Parsing otherName for subject alternative names: " + objectId.toString() ); Log.debug("Parsing otherName for subject alternative names: " + objectId.toString() );
if ( !OTHERNAME_XMPP_OID.equals(objectId.getId())) { // Get identity string
if ( OTHERNAME_SRV_OID.equals(objectId.getId())) {
return parseOtherNameDnsSrv( otherNameSeq );
} else if ( OTHERNAME_XMPP_OID.equals(objectId.getId())) {
// Not a XMPP otherName // Not a XMPP otherName
Log.debug("Ignoring non-XMPP otherName, " + objectId.getId()); return parseOtherNameXmppAddr( otherNameSeq );
} else
{
Log.debug("Ignoring otherName '{}' that's neither id-on-xmppAddr nor id-on-dnsSRV.", objectId.getId());
return null; return null;
} }
// Get identity string
try {
final String identity;
ASN1Encodable o = otherNameSeq.getObjectAt(1);
if (o instanceof DERTaggedObject) {
ASN1TaggedObject ato = DERTaggedObject.getInstance(o);
Log.debug("... processing DERTaggedObject: " + ato.toString());
// TODO: there's bound to be a better way...
identity = ato.toString().substring(ato.toString().lastIndexOf(']')+1).trim();
} else {
DERUTF8String derStr = DERUTF8String.getInstance(o);
identity = derStr.getString();
}
if (identity != null && identity.length() > 0) {
// Add the decoded server name to the list of identities
return identity;
}
} catch (IllegalArgumentException ex) {
// OF-517: othername formats are extensible. If we don't recognize the format, skip it.
Log.debug("Cannot parse altName, likely because of unknown record format.", ex);
}
} }
catch (Exception e) { catch (Exception e) {
Log.error("Error decoding subjectAltName", e); Log.error("Error decoding subjectAltName", e);
...@@ -144,4 +149,54 @@ public class SANCertificateIdentityMapping implements CertificateIdentityMapping ...@@ -144,4 +149,54 @@ public class SANCertificateIdentityMapping implements CertificateIdentityMapping
return null; return null;
} }
public static String parseOtherNameDnsSrv( ASN1Sequence otherNameSeq )
{
Log.debug( "Parsing SRVName otherName..." );
try {
final ASN1Encodable o = otherNameSeq.getObjectAt( 1 );
final DERUTF8String derStr = DERUTF8String.getInstance( o );
final String value = derStr.getString();
if ( value.startsWith( "_xmpp-server." )) {
Log.debug( "Found _xmpp-server SRVName otherName" );
return value.substring( "_xmpp-server.".length() );
}
if ( value.startsWith( "_xmpp-client." )) {
Log.debug( "Found _xmpp-client SRVName otherName" );
return value.substring( "_xmpp-client.".length() );
}
else
{
Log.debug( "SRVName otherName '{}' was neither _xmpp-server nor _xmpp-client. It is being ignored.", value );
return null;
}
} catch (IllegalArgumentException ex) {
Log.debug("Cannot parse id-on-dnsSRV otherName, likely because of unknown record format.", ex);
return null;
}
}
public static String parseOtherNameXmppAddr( ASN1Sequence otherNameSeq )
{
try {
final String identity;
ASN1Encodable o = otherNameSeq.getObjectAt(1);
if (o instanceof DERTaggedObject) {
ASN1TaggedObject ato = DERTaggedObject.getInstance(o);
Log.debug("... processing DERTaggedObject: " + ato.toString());
// TODO: there's bound to be a better way...
identity = ato.toString().substring(ato.toString().lastIndexOf(']')+1).trim();
} else {
DERUTF8String derStr = DERUTF8String.getInstance(o);
identity = derStr.getString();
}
if (identity != null && identity.length() > 0) {
// Add the decoded server name to the list of identities
return identity;
}
} catch (IllegalArgumentException ex) {
// OF-517: othername formats are extensible. If we don't recognize the format, skip it.
Log.debug("Cannot parse id-on-xmppAddr otherName, likely because of unknown record format.", ex);
}
return null;
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment