/* WolfSSLX509Name.java * * Copyright (C) 2006-2025 wolfSSL Inc. * * This file is part of wolfSSL. * * wolfSSL is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * wolfSSL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ package com.wolfssl; /** * WolfSSLX509Name class, wraps native WOLFSSL_X509_NAME functionality. */ public class WolfSSLX509Name { private boolean active = false; private long x509NamePtr = 0; /* Lock around active state */ private final Object stateLock = new Object(); /* Lock around x509NamePtr pointer access */ private final Object x509NameLock = new Object(); /* Cache name elements in Java before pushing through JNI, for easier * retrieval from getXXX() methods */ private String countryName = null; private String stateOrProvinceName = null; private String streetAddress = null; private String localityName = null; private String surname = null; private String commonName = null; private String emailAddress = null; private String organizationName = null; private String organizationalUnitName = null; private String postalCode = null; private String userId = null; /* Encoding types, matched to native define values */ private static final int MBSTRING_UTF8 = 0x100; /* Native JNI methods */ static native long X509_NAME_new(); static native void X509_NAME_free(long x509Name); static native int X509_NAME_add_entry_by_txt(long x509Name, String field, int type, byte[] entry, int len, int loc, int set); /** * Create new empty WolfSSLX509Name object. * * @throws WolfSSLException if native API call fails. */ public WolfSSLX509Name() throws WolfSSLException { x509NamePtr = X509_NAME_new(); if (x509NamePtr == 0) { throw new WolfSSLException("Failed to create WolfSSLX509Name"); } WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI, WolfSSLDebug.INFO, x509NamePtr, () -> "creating new WolfSSLX509Name"); synchronized (stateLock) { this.active = true; } } /** * Verifies that the current WolfSSLX509Name object is active. * * @throws IllegalStateException if object has been freed */ private void confirmObjectIsActive() throws IllegalStateException { synchronized (stateLock) { if (this.active == false) { throw new IllegalStateException( "WolfSSLX509Name object has been freed"); } } } /** * For package use only, return native WOLFSSL_X509_NAME pointer. * * @return native WOLFSSL_X509_POINTER value * @throws IllegalStateException if WolfSSLX509Name has been freed. */ protected long getNativeX509NamePtr() throws IllegalStateException { confirmObjectIsActive(); /* TODO lock around x509NamePtr for caller use */ synchronized (x509NameLock) { return this.x509NamePtr; } } /** * Private helper function to call native JNI function * X509_NAME_add_entry_by_txt(). * * @param field String containing field name to set, for example * "countryName" * @param entry String value to store into field * * @throws WolfSSLException if arguments are invalid or error occurs * with native JNI call. */ private synchronized void addEntryByTxt(String field, String entry) throws WolfSSLException { int ret = 0; if (field == null || entry == null) { throw new WolfSSLException( "field or entry is null in addEntryByTxt()"); } synchronized (x509NameLock) { ret = X509_NAME_add_entry_by_txt(this.x509NamePtr, field, MBSTRING_UTF8, entry.getBytes(), entry.getBytes().length, -1, 0); } if (ret != WolfSSL.SSL_SUCCESS) { throw new WolfSSLException("Error setting " + field + " into WolfSSLX509Name (error: " + ret + ")"); } } /** * Set country name for this name object. * * @param countryName String containing country name to be set * * @throws IllegalStateException if WolfSSLX509Name has been freed. * @throws WolfSSLException if native JNI error has occurred, or input * argument is invalid. */ public synchronized void setCountryName(String countryName) throws IllegalStateException, WolfSSLException { confirmObjectIsActive(); WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI, WolfSSLDebug.INFO, this.x509NamePtr, () -> "entered setCountryName(" + countryName + ")"); addEntryByTxt("countryName", countryName); this.countryName = countryName; } /** * Set state or province name for this name object. * * @param name String containing state or province name to be set * * @throws IllegalStateException if WolfSSLX509Name has been freed. * @throws WolfSSLException if native JNI error has occurred, or input * argument is invalid. */ public synchronized void setStateOrProvinceName(String name) throws IllegalStateException, WolfSSLException { confirmObjectIsActive(); WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI, WolfSSLDebug.INFO, this.x509NamePtr, () -> "entered setStateOrProvinceName(" + name + ")"); addEntryByTxt("stateOrProvinceName", name); this.stateOrProvinceName = name; } /** * Set street address for this name object. * * @param address String containing street address to be set * * @throws IllegalStateException if WolfSSLX509Name has been freed. * @throws WolfSSLException if native JNI error has occurred, or input * argument is invalid. */ public synchronized void setStreetAddress(String address) throws IllegalStateException, WolfSSLException { confirmObjectIsActive(); WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI, WolfSSLDebug.INFO, this.x509NamePtr, () -> "entered setStreetAddress(" + address + ")"); addEntryByTxt("streetAddress", address); this.streetAddress = address; } /** * Set locality name / city for this name object. * * @param name String containing locality name to be set * * @throws IllegalStateException if WolfSSLX509Name has been freed. * @throws WolfSSLException if native JNI error has occurred, or input * argument is invalid. */ public synchronized void setLocalityName(String name) throws IllegalStateException, WolfSSLException { confirmObjectIsActive(); WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI, WolfSSLDebug.INFO, this.x509NamePtr, () -> "entered setLocalityName(" + name + ")"); addEntryByTxt("localityName", name); this.localityName = name; } /** * Set surname for this name object. * * @param name String containing surname to be set * * @throws IllegalStateException if WolfSSLX509Name has been freed. * @throws WolfSSLException if native JNI error has occurred, or input * argument is invalid. */ public synchronized void setSurname(String name) throws IllegalStateException, WolfSSLException { confirmObjectIsActive(); WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI, WolfSSLDebug.INFO, this.x509NamePtr, () -> "entered setSurname(" + name + ")"); addEntryByTxt("surname", name); this.surname = name; } /** * Set common name for this name object. * * @param name String containing common name to be set * * @throws IllegalStateException if WolfSSLX509Name has been freed. * @throws WolfSSLException if native JNI error has occurred, or input * argument is invalid. */ public synchronized void setCommonName(String name) throws IllegalStateException, WolfSSLException { confirmObjectIsActive(); WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI, WolfSSLDebug.INFO, this.x509NamePtr, () -> "entered setCommonName(" + name + ")"); addEntryByTxt("commonName", name); this.commonName = name; } /** * Set email address for this name object. * * @param email String containing email address to be set * * @throws IllegalStateException if WolfSSLX509Name has been freed. * @throws WolfSSLException if native JNI error has occurred, or input * argument is invalid. */ public synchronized void setEmailAddress(String email) throws IllegalStateException, WolfSSLException { confirmObjectIsActive(); WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI, WolfSSLDebug.INFO, this.x509NamePtr, () -> "entered setEmailAddress(" + email + ")"); addEntryByTxt("emailAddress", email); this.emailAddress = email; } /** * Set organization name for this name object. * * @param name String containing organization name to be set * * @throws IllegalStateException if WolfSSLX509Name has been freed. * @throws WolfSSLException if native JNI error has occurred, or input * argument is invalid. */ public synchronized void setOrganizationName(String name) throws IllegalStateException, WolfSSLException { confirmObjectIsActive(); WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI, WolfSSLDebug.INFO, this.x509NamePtr, () -> "entered setOrganizationName(" + name + ")"); addEntryByTxt("organizationName", name); this.organizationName = name; } /** * Set organizational unit name for this name object. * * @param name String containing organizational unit name to be set * * @throws IllegalStateException if WolfSSLX509Name has been freed. * @throws WolfSSLException if native JNI error has occurred, or input * argument is invalid. */ public synchronized void setOrganizationalUnitName(String name) throws IllegalStateException, WolfSSLException { confirmObjectIsActive(); WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI, WolfSSLDebug.INFO, this.x509NamePtr, () -> "entered setOrganizationalUnitName(" + name + ")"); addEntryByTxt("organizationalUnitName", name); this.organizationalUnitName = name; } /** * Set postal code for this name object. * * @param code String containing postal code to be set * * @throws IllegalStateException if WolfSSLX509Name has been freed. * @throws WolfSSLException if native JNI error has occurred, or input * argument is invalid. */ public synchronized void setPostalCode(String code) throws IllegalStateException, WolfSSLException { confirmObjectIsActive(); WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI, WolfSSLDebug.INFO, this.x509NamePtr, () -> "entered setPostalCode(" + code + ")"); addEntryByTxt("postalCode", code); this.postalCode = code; } /** * Set user ID for this name object. * * @param id String containing user ID to be set * * @throws IllegalStateException if WolfSSLX509Name has been freed. * @throws WolfSSLException if native JNI error has occurred, or input * argument is invalid. */ public synchronized void setUserId(String id) throws IllegalStateException, WolfSSLException { confirmObjectIsActive(); WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI, WolfSSLDebug.INFO, this.x509NamePtr, () -> "entered setUserId(" + id + ")"); addEntryByTxt("userId", id); this.userId = id; } /** * Get country name set in this object. * * @return country name string, or null if not yet set * * @throws IllegalStateException if WolfSSLX509Name has been freed. */ public synchronized String getCountryName() { confirmObjectIsActive(); WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI, WolfSSLDebug.INFO, this.x509NamePtr, () -> "entered getCountryName()"); return this.countryName; } /** * Get state or province name set in this object. * * @return state or province name string, or null if not yet set * * @throws IllegalStateException if WolfSSLX509Name has been freed. */ public synchronized String getStateOrProvinceName() { confirmObjectIsActive(); WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI, WolfSSLDebug.INFO, this.x509NamePtr, () -> "entered getStateOrProvinceName()"); return this.stateOrProvinceName; } /** * Get street address set in this object. * * @return street address string, or null if not yet set * * @throws IllegalStateException if WolfSSLX509Name has been freed. */ public synchronized String getStreetAddress() { confirmObjectIsActive(); WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI, WolfSSLDebug.INFO, this.x509NamePtr, () -> "entered getStreetAddress()"); return this.streetAddress; } /** * Get locality name set in this object. * * @return locality name string, or null if not yet set * * @throws IllegalStateException if WolfSSLX509Name has been freed. */ public synchronized String getLocalityName() { confirmObjectIsActive(); WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI, WolfSSLDebug.INFO, this.x509NamePtr, () -> "entered getLocalityName()"); return this.localityName; } /** * Get surname set in this object. * * @return surname string, or null if not yet set * * @throws IllegalStateException if WolfSSLX509Name has been freed. */ public synchronized String getSurname() { confirmObjectIsActive(); WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI, WolfSSLDebug.INFO, this.x509NamePtr, () -> "entered getSurname()"); return this.surname; } /** * Get common name set in this object. * * @return common name string, or null if not yet set * * @throws IllegalStateException if WolfSSLX509Name has been freed. */ public synchronized String getCommonName() { confirmObjectIsActive(); WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI, WolfSSLDebug.INFO, this.x509NamePtr, () -> "entered getCommonName()"); return this.commonName; } /** * Get email address set in this object. * * @return email address string, or null if not yet set * * @throws IllegalStateException if WolfSSLX509Name has been freed. */ public synchronized String getEmailAddress() { confirmObjectIsActive(); WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI, WolfSSLDebug.INFO, this.x509NamePtr, () -> "entered getEmailAddress()"); return this.emailAddress; } /** * Get organization name set in this object. * * @return organization name string, or null if not yet set * * @throws IllegalStateException if WolfSSLX509Name has been freed. */ public synchronized String getOrganizationName() { confirmObjectIsActive(); WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI, WolfSSLDebug.INFO, this.x509NamePtr, () -> "entered getOrganizationName()"); return this.organizationName; } /** * Get organizational unit name set in this object. * * @return organizational unit name string, or null if not yet set * * @throws IllegalStateException if WolfSSLX509Name has been freed. */ public synchronized String getOrganizationalUnitName() { confirmObjectIsActive(); WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI, WolfSSLDebug.INFO, this.x509NamePtr, () -> "entered getOrganizationalUnitName()"); return this.organizationalUnitName; } /** * Get postal code set in this object. * * @return postal code string, or null if not yet set * * @throws IllegalStateException if WolfSSLX509Name has been freed. */ public synchronized String getPostalCode() { confirmObjectIsActive(); WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI, WolfSSLDebug.INFO, this.x509NamePtr, () -> "entered getPostalCode()"); return this.postalCode; } /** * Get user ID set in this object. * * @return user ID string, or null if not yet set * * @throws IllegalStateException if WolfSSLX509Name has been freed. */ public synchronized String getUserId() { confirmObjectIsActive(); WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI, WolfSSLDebug.INFO, this.x509NamePtr, () -> "entered getUserId()"); return this.userId; } @Override public String toString() { synchronized (stateLock) { if (this.active == false) { return ""; } } /* TODO: wrap wolfSSL_X509_NAME_oneline() */ return ""; } /** * Free native resources of WolfSSLX509Name. */ public synchronized void free() { synchronized (stateLock) { if (this.active == false) { /* already freed, just return */ return; } synchronized (x509NameLock) { WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI, WolfSSLDebug.INFO, this.x509NamePtr, () -> "entered free()"); /* free native resources */ X509_NAME_free(this.x509NamePtr); this.active = false; this.x509NamePtr = 0; } } } @SuppressWarnings("deprecation") @Override protected void finalize() throws Throwable { this.free(); super.finalize(); } }