Adding a new Extension to my generated certificate
Note: for these codes I used bcprov-jdk15on 1.56
Some comments about your code. First of all, note the ASN1 structure:
TNAuthorizationList ::= SEQUENCE SIZE (1..MAX) OF TNEntry
TNEntry ::= CHOICE {
spc [0] ServiceProviderCodeList,
range [1] TelephoneNumberRange,
one E164Number
}
Note that TNEntry
is a choice, and TNAuthorizationList
is a sequence of TNEntry
objects. So your class name should be changed to TNEntry
. In the code below, please remember that I've changed the class name to TNEntry
.
I've also changed some things in this class. In getInstance(Object obj)
method, the types of spc and range fields are incorrect (according to ASN1 definition, they are both sequences):
switch (tag) {
case spc:
case range: // both are sequences
return new TNEntry(tag, ASN1Sequence.getInstance(tagObj, false));
// not sure about "one" field, as it's not tagged
}
I just don't know how to handle the one field, as it's not tagged. Maybe it should be a DERIA5String
, or maybe there's another type for "untagged" choices.
In this same class (remember, I've changed its name to TNEntry
), I also removed the constructor public TNEntry(int tag, String name)
because I'm not sure if it applies (at least I didn't need to use it, but you can keep it if you want), and I've changed toString
method to return a more readable string:
public String toString() {
String sep = System.getProperty("line.separator");
StringBuffer buf = new StringBuffer();
buf.append(this.getClass().getSimpleName());
buf.append(" [").append(tag);
buf.append("]: ");
switch (tag) {
case spc:
buf.append("ServiceProviderCodeList: ").append(sep);
ASN1Sequence seq = (ASN1Sequence) this.obj;
int size = seq.size();
for (int i = 0; i < size; i++) {
// all elements are DERIA5Strings
DERIA5String str = (DERIA5String) seq.getObjectAt(i);
buf.append(" ");
buf.append(str.getString());
buf.append(sep);
}
break;
case range:
buf.append("TelephoneNumberRange: ").append(sep);
// there are always 2 elements in TelephoneNumberRange
ASN1Sequence s = (ASN1Sequence) this.obj;
DERIA5String str = (DERIA5String) s.getObjectAt(0);
buf.append(" start: ");
buf.append(str.getString());
buf.append(sep);
ASN1Integer count = (ASN1Integer) s.getObjectAt(1);
buf.append(" count: ");
buf.append(count.toString());
buf.append(sep);
break;
default:
buf.append(obj.toString());
}
return buf.toString();
}
And I also created a TNAuthorizationList
class, which holds the sequence of TNEntry
objects (remember that I've changed your class name to TNEntry
, so this TNAuthorizationList
class is a different one). Note that I also created a constant to hold the OID (just to make things a little bit easier):
public class TNAuthorizationList extends ASN1Object {
// put OID in a constant, so I don't have to remember it all the time
public static final ASN1ObjectIdentifier TN_AUTH_LIST_OID = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.26");
private TNEntry[] entries;
public TNAuthorizationList(TNEntry[] entries) {
this.entries = entries;
}
public static TNAuthorizationList getInstance(Object obj) {
if (obj instanceof TNAuthorizationList) {
return (TNAuthorizationList) obj;
}
if (obj != null) {
return new TNAuthorizationList(ASN1Sequence.getInstance(obj));
}
return null;
}
public static TNAuthorizationList getInstance(ASN1TaggedObject obj, boolean explicit) {
return getInstance(ASN1Sequence.getInstance(obj, explicit));
}
private TNAuthorizationList(ASN1Sequence seq) {
this.entries = new TNEntry[seq.size()];
for (int i = 0; i != seq.size(); i++) {
entries[i] = TNEntry.getInstance(seq.getObjectAt(i));
}
}
public TNEntry[] getEntries() {
TNEntry[] tmp = new TNEntry[entries.length];
System.arraycopy(entries, 0, tmp, 0, entries.length);
return tmp;
}
@Override
public ASN1Primitive toASN1Primitive() {
return new DERSequence(entries);
}
public String toString() {
String sep = System.getProperty("line.separator");
StringBuffer buf = new StringBuffer();
buf.append(this.getClass().getSimpleName());
buf.append(":").append(sep);
for (TNEntry tnEntry : entries) {
buf.append(" ");
buf.append(tnEntry.toString());
buf.append(sep);
}
return buf.toString();
}
}
Now, to add this extension to a certificate, I've done this code (with some sample data as I don't know what should be in each field in a real world situation):
X509v3CertificateBuilder builder = new JcaX509v3CertificateBuilder(etc...);
// create TNEntries for TNAuthorizationList
TNEntry[] entries = new TNEntry[2];
// create a "spc" entry
DERIA5String[] cList = new DERIA5String[] { new DERIA5String("spc1"), new DERIA5String("spc2") };
DERSequence spc = new DERSequence(cList);
entries[0] = TNEntry.getInstance(new DERTaggedObject(false, TNEntry.spc, spc));
// create a "range" entry
DERSequence range = new DERSequence(new ASN1Encodable[] { new DERIA5String("123456"), new ASN1Integer(1) });
entries[1] = TNEntry.getInstance(new DERTaggedObject(false, TNEntry.range, range));
TNAuthorizationList tnAuthList = new TNAuthorizationList(entries);
builder.addExtension(TNAuthorizationList.TN_AUTH_LIST_OID, false, tnAuthList);
Once you have the certificate object (a X509Certificate
in my example), you can do:
// cert is a X509Certificate instance
ASN1Primitive value = X509ExtensionUtil.fromExtensionValue(cert.getExtensionValue(TNAuthorizationList.TN_AUTH_LIST_OID.getId()));
TNAuthorizationList authList = TNAuthorizationList.getInstance(value);
System.out.println(authList.toString());
The output will be:
TNAuthorizationList:
TNEntry [0]: ServiceProviderCodeList:
spc1
spc2
TNEntry [1]: TelephoneNumberRange:
start: 123456
count: 1
Notes:
- As I said, this code is incomplete because I'm not sure how to handle the one field of
TNEntry
, because it's not tagged (I don't know if it must be aDERIA5String
or if there's another type of object for an "untagged" field). - You could also do some improvements:
ServiceProviderCodeList
can have 1 to 3 elements, so you could validate its sizeTelephoneNumberRange
: the start field has a specific format (FROM ("0123456789#*")
which I think it means only these characters are accepted), so you could also validate it- To create the values for
ServiceProviderCodeList
andTelephoneNumberRange
, I've created theDERSequence
objects by hand, but you can create custom classes for them if you want:ServiceProviderCodeList
could hold a list ofDERIA5String
and perform proper validations in its constructor (size from 1 to 3), andTelephoneNumberRange
could have start and count fields (with proper validation of start value) - andtoASN1Primitive
just need to return aDERSequence
of its fields in the right order
For your parsing issues, I've checked acme4j code and it uses a java.security.cert.X509Certificate
class. The toString()
method of this class (when using Sun's default provider) is generating this "extension unknown" output (according to the corresponding code).
So, in order to parse it correctly (show the formatted output as described above), you'll probably have to change acme4j's code (or write your own), creating a new toString()
method and include the new TNAuthorizationList
classes in this method.
When you provide the code showing how you're using acme4j, I'll update this answer accordingly, if needed.
How to generate a self-signed SSL certificate using OpenSSL?
You can do that in one command:
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 365
You can also add -nodes
(short for "no DES") if you don't want to protect your private key with a passphrase. Otherwise it will prompt you for "at least a 4 character" password.
The days
parameter (365) you can replace with any number to affect the expiration date. It will then prompt you for things like "Country Name", but you can just hit Enter and accept the defaults.
Add -subj '/CN=localhost'
to suppress questions about the contents of the certificate (replace localhost
with your desired domain).
Self-signed certificates are not validated with any third party unless you import them to the browsers previously. If you need more security, you should use a certificate signed by a certificate authority (CA).
How to set the Keyusage value to new openssl X509 certificate in c program?
By Adding the below functionality we can get the key usages, basic constraints to our created certificate....
int add_ext ( X509 *cert, int nid, char *value );
// Local variable definition
INT nid = 0;
// add algorithms to internal table
OpenSSL_add_all_algorithms( );
OpenSSL_add_all_ciphers ( );
OpenSSL_add_all_digests ( );
// A CA certificate must include the basicConstraints value with the
// CA field set to TRUE.
add_ext ( xcert, NID_basic_constraints, "critical,CA:TRUE" );
// Key usage is a multi valued extension consisting of a list of names
// of the permitted key usages.
add_ext ( xcert, NID_key_usage, "digitalSignature, nonRepudiation" );
// This Extensions consists of a list of usages indicating purposes for
// which the certificate public key can be used for..
add_ext ( xcert, NID_ext_key_usage, "critical,codeSigning,1.2.3.4" );
// Adds a new object to the internal table. oid is the numerical form
// of the object, sn the short name and ln the long name.
nid = OBJ_create ( "1.2.3.4", "SAMP_OID", "Test_OID" );
X509V3_EXT_add_alias ( nid, NID_netscape_comment );
add_ext ( xcert, nid, "MQ Comment Section" );
User defined function
---------------------
// Add extension using V3 code: we can set the config file as NULL because we
// wont reference any other sections.
int add_ext ( X509 *cert, int nid, char *value )
{
//
// Local Variable Definitions
//
X509_EXTENSION *ex = NULL;
X509V3_CTX ctx;
// Setting context of Extension
X509V3_set_ctx_nodb ( &ctx );
// Issuer and subject certs: both the target since it is self signed, no
// request and no CRL
X509V3_set_ctx( &ctx, cert, cert, NULL, NULL, NULL );
ex = X509V3_EXT_conf_nid (NULL, &ctx, nid, value );
if( !ex )
{
printf( "tError: In X509V3_EXT_conf_nidn" );
hResult= GetLastError( );
}
return 0;
}
Related Topics
How to Delay Pipe Netcat to Connect on First Input
How to Add a Ppa Repository Using Ansible
Restoring System Directories Permissions
Sorting in Fortran, Undefined Reference to Qsort_
/Usr/Bin/Ld: Cannot Find -Lglut
Range: Bytes 0- Fails in Apache 2.2.23
Unexpected Eof While Looking for Matching '"'
Rmpi: Cannot Use Mpi_Comm_Spawn API
Golang Math Can Not Finished with My Code, But Python Is Ok
Vfs: File-Max Limit 1231582 Reached
How to Run a Linux Executable from Any Directory in Terminal
Gitlab Ce Doesn't Add a Public Key to Authorized_Keys
Arm Linux ":Start_Kernel Is Not Calling After Decompressing UImage"
Git Says Everything Up-To-Date
Dreamweaver Equivalent for Linux
Omnibus or Source - Can't Decide Which One to Use for Gitllab Backup/Restore