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,18 +18,35 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Certificate identity mapping that uses SubjectAlternativeName as the identity credentials. This implementation
* combines subjectAltName entries of type otherName with an ASN.1 Object Identifier of "id-on-xmppAddr" with entries
* of type DNS.
* Certificate identity mapping that uses SubjectAlternativeName as the identity credentials.
* This implementation returns all subjectAltName entries that are a:
* <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 Guus der Kinderen, guus@goodbytes.nl
*/
public class SANCertificateIdentityMapping implements CertificateIdentityMapping {
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
......@@ -54,15 +71,19 @@ public class SANCertificateIdentityMapping implements CertificateIdentityMapping
final String result;
switch ( type ) {
case 0:
// OtherName: search for "id-on-xmppAddr"
// OtherName: search for "id-on-xmppAddr" or 'sRVName'
result = parseOtherName( (byte[]) value );
break;
case 2:
// DNS
result = (String) value;
break;
case 6:
// URI
result = (String) value;
break;
default:
// Other types are not applicable for XMPP, so silently ignore them
// Not applicable to XMPP, so silently ignore them
result = null;
break;
}
......@@ -100,7 +121,7 @@ public class SANCertificateIdentityMapping implements CertificateIdentityMapping
try (ASN1InputStream decoder = new ASN1InputStream(item)) {
// Value is encoded using ASN.1 so decode it to get the server's identity
Object object = decoder.readObject();
ASN1Sequence otherNameSeq = null;
ASN1Sequence otherNameSeq;
if (object != null && object instanceof ASN1Sequence) {
otherNameSeq = (ASN1Sequence) object;
} else {
......@@ -110,13 +131,52 @@ public class SANCertificateIdentityMapping implements CertificateIdentityMapping
ASN1ObjectIdentifier objectId = (ASN1ObjectIdentifier) otherNameSeq.getObjectAt(0);
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
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;
}
}
catch (Exception e) {
Log.error("Error decoding subjectAltName", e);
}
return null;
}
// Get identity string
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);
......@@ -135,13 +195,8 @@ public class SANCertificateIdentityMapping implements CertificateIdentityMapping
}
} 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) {
Log.error("Error decoding subjectAltName", e);
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