org.snmp4j.transport.tls.DefaultTlsTmSecurityCallback Maven / Gradle / Ivy
/*_############################################################################
_##
_## SNMP4J 2 - DefaultTlsTmSecurityCallback.java
_##
_## Copyright (C) 2003-2016 Frank Fock and Jochen Katz (SNMP4J.org)
_##
_## Licensed under the Apache License, Version 2.0 (the "License");
_## you may not use this file except in compliance with the License.
_## You may obtain a copy of the License at
_##
_## http://www.apache.org/licenses/LICENSE-2.0
_##
_## Unless required by applicable law or agreed to in writing, software
_## distributed under the License is distributed on an "AS IS" BASIS,
_## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
_## See the License for the specific language governing permissions and
_## limitations under the License.
_##
_##########################################################################*/
package org.snmp4j.transport.tls;
import org.snmp4j.log.LogAdapter;
import org.snmp4j.log.LogFactory;
import org.snmp4j.smi.Address;
import org.snmp4j.smi.OctetString;
import org.snmp4j.transport.TLSTM;
import javax.security.auth.x500.X500Principal;
import java.security.Principal;
import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
import java.util.*;
/**
* The DefaultTlsTmSecurityCallback
resolves the
* tmSecurityName
for incoming requests through
* a mapping table based on the peer certificates,
* resolves the local certificate alias through a mapping table
* based on the target address and accepts peer certificates
* based on a list of trusted peer and issuer certificates.
*
* @author Frank Fock
* @since 2.0
*/
public class DefaultTlsTmSecurityCallback implements TlsTmSecurityCallback {
private LogAdapter LOGGER = LogFactory.getLogger(DefaultTlsTmSecurityCallback.class);
private Map securityNameMapping = new HashMap();
private Map localCertMapping = new HashMap();
private Set acceptedSubjectDN = new HashSet();
private Set acceptedIssuerDN = new HashSet();
@Override
public OctetString getSecurityName(X509Certificate[] peerCertificateChain) {
for (Map.Entry entry : securityNameMapping.entrySet()) {
OctetString fingerprint = entry.getKey().getFingerprint();
for (X509Certificate cert : peerCertificateChain) {
OctetString certFingerprint = null;
certFingerprint = TLSTM.getFingerprint(cert);
if ((certFingerprint != null) && (certFingerprint.equals(fingerprint))) {
// possible match found -> now try to map to tmSecurityName
org.snmp4j.transport.tls.SecurityNameMapping.CertMappingType mappingType = entry.getKey().getType();
OctetString data = entry.getKey().getData();
OctetString tmSecurityName = null;
try {
tmSecurityName = mapCertToTSN(cert, mappingType, data);
} catch (CertificateParsingException e) {
LOGGER.warn("Failed to parse client certificate: " + e.getMessage());
}
if ((tmSecurityName != null) && (tmSecurityName.length() <= 32)) {
return tmSecurityName;
}
}
}
}
return null;
}
private OctetString mapCertToTSN(X509Certificate cert,
org.snmp4j.transport.tls.SecurityNameMapping.CertMappingType mappingType, OctetString data)
throws CertificateParsingException
{
switch (mappingType) {
case Specified: {
return data;
}
case SANAny:
case SANRFC822Name: {
Object entry = TLSTM.getSubjAltName(cert.getSubjectAlternativeNames(), 1);
if (entry != null) {
String[] rfc822Name = ((String)entry).split("@");
return new OctetString(rfc822Name[0]+"@"+rfc822Name[1].toLowerCase());
}
// fall through SANAny
}
case SANDNSName: {
Object entry = TLSTM.getSubjAltName(cert.getSubjectAlternativeNames(), 2);
if (entry != null) {
String dNSName = ((String)entry).toLowerCase();
return new OctetString(dNSName);
}
}
case SANIpAddress: {
Object entry = TLSTM.getSubjAltName(cert.getSubjectAlternativeNames(), 7);
if (entry != null) {
String ipAddress = ((String)entry).toLowerCase();
if (ipAddress.indexOf(':')>=0) {
// IPv6 address
StringBuilder buf = new StringBuilder(16);
String[] bytes = ipAddress.split(":");
for (String b : bytes) {
for (int diff = 2-b.length(); diff>0; diff--) {
buf.append('0');
}
buf.append(b);
}
return new OctetString(buf.toString());
}
return new OctetString(ipAddress);
}
}
case CommonName: {
X500Principal x500Principal = cert.getSubjectX500Principal();
return new OctetString(x500Principal.getName());
}
}
return null;
}
@Override
public boolean isClientCertificateAccepted(X509Certificate peerEndCertificate) {
return acceptedSubjectDN.contains(peerEndCertificate.getSubjectDN().getName());
}
@Override
public boolean isServerCertificateAccepted(X509Certificate[] peerCertificateChain) {
String subject = peerCertificateChain[0].getSubjectDN().getName();
if (acceptedSubjectDN.contains(subject)) {
return true;
}
for (X509Certificate cert : peerCertificateChain) {
Principal issuerDN = cert.getIssuerDN();
if ((issuerDN != null) && acceptedIssuerDN.contains(issuerDN.getName())) {
return true;
}
}
return false;
}
@Override
public boolean isAcceptedIssuer(X509Certificate issuerCertificate) {
Principal issuerDN = issuerCertificate.getIssuerDN();
return ((issuerDN != null) && acceptedIssuerDN.contains(issuerDN.getName()));
}
@Override
public String getLocalCertificateAlias(Address targetAddress) {
String localCert = localCertMapping.get(targetAddress);
if (localCert == null) {
return localCertMapping.get(null);
}
return localCert;
}
/**
* Adds a mapping to derive a security name from a certificate. A mapping corresponds to a row
* in the snmpTlstmCertToTSNTable of RFC 5953.
*
* @param fingerprint
* an (optional) cryptographic hash of a X.509 certificate. Whether the trusted CA in
* the certificate validation path or the certificate itself is matched against the
* fingerprint is specified by the type
parameter.
* @param type
* specifies the mapping type of the security name derivation from a certificate.
* @param data
* auxiliary data used as optional configuration information for some mapping types.
* It must be ignored for any mapping type that does not use auxiliary data.
* @param securityName
* specifies the mapped security name. This parameter is optional and only required if
* the mapping type does not dictate a method to derive the security name from a
* certificates meta data (like subjectAltName).
*/
public void addSecurityNameMapping(OctetString fingerprint,
org.snmp4j.transport.tls.SecurityNameMapping.CertMappingType type,
OctetString data,
OctetString securityName) {
securityNameMapping.put(new SecurityNameMapping(fingerprint, data, type, securityName), securityName);
}
public OctetString removeSecurityNameMapping(OctetString fingerprint, org.snmp4j.transport.tls.SecurityNameMapping.CertMappingType type, OctetString data) {
return securityNameMapping.remove(new SecurityNameMapping(fingerprint, data, type, null));
}
public void addAcceptedIssuerDN(String issuerDN) {
acceptedIssuerDN.add(issuerDN);
}
public boolean removeAcceptedIssuerDN(String issuerDN) {
return acceptedIssuerDN.remove(issuerDN);
}
public void addAcceptedSubjectDN(String subjectDN) {
acceptedSubjectDN.add(subjectDN);
}
public boolean removeAcceptedSubjectDN(String subjectDN) {
return acceptedSubjectDN.remove(subjectDN);
}
/**
* Map a target address to a local certificate alias. The security mapping
* will use the certificate certAlias
for a target address
* address
when applied to a client mode {@link TLSTM}.
* @param address
* a {@link org.snmp4j.smi.TlsAddress} instance or null
* if the local certificate should mapped to any target address.
* @param certAlias
* the certificate alias in the local key store to be used to authenticate
* at TLS server instances.
*/
public void addLocalCertMapping(Address address, String certAlias) {
localCertMapping.put(address, certAlias);
}
/**
* Remove the local certificate mapping for the given target address.
* @param address
* a {@link org.snmp4j.smi.TlsAddress} instance or null
* if the default local certificate mapping should be removed.
* @return
* the removed mapping or null
if there is no such mapping.
*/
public String removeLocalCertMapping(Address address) {
return localCertMapping.remove(address);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy