How to get BasicConstraints extension from Java X509 certificate - java

I would like to read the extension BasicConstraints from Java X509Certificate (the certificate implementation comes from default JCE so it is sun.security.x509.X509CertImpl).
I wanted to get the BasicConstraint extension value to check if it is CA :
X509Certificate certificate = ...
byte[] basicConstraint = certificate.getExtensionValue("2.5.29.19");
But this gives me byte array that contains DEROctetString. And after unwrapping it I get byte array with 2 bytes.
However the extension BasicConstraint seems to be defined as :
BasicConstraints := SEQUENCE {
cA BOOLEAN DEFAULT FALSE,
pathLenConstraint INTEGER (0..MAX) OPTIONAL
}
I have already looked at X509Certificate::getBasicConstraints() method which returns an int. The problem is that it also returns -1 when the extension is not present.
That is why I am looking for a way to get this ASN1 sequence from X509 certificate to explicitly check this CA boolean flag.

The valid encodings of the BasicConstraints extension (within the OCTET STRING) are:
CA=false: 30 00
CA=true, pathlen omitted: 30 03 01 01 FF
CA=true, pathlen=0 to 127: 30 06 01 01 FF 02 01 xx
CA=true, pathlen >= 128: using such long paths is so silly I omit this case, but you can work it out using the DER rules if you really want
You most likely have case 1.

Related

How to convert rtp packet payload bytes H264/90000 to any video data?

Studying the sip protocol, I got to the topic of the H264 codec. I began to receive data in the form of rtp packets. I managed to successfully get the following data from the package: Payload type (in my case 97), Timestamp, Sequence number and payload data (byte array). Next, I want to draw images encoded in this data. On the android platform, I use the android.media.MediaCodec class. I follow examples like MediaCodec failing on S7.
I create an instance of MediaCodec. Configuring with MediaFormat. Then I transfer the received bytes to inputBuffer and wait for updates via dequeueOutputBuffer. In my case, the dequeueOutputBuffer method always returns MediaCodec.INFO_TRY_AGAIN_LATER.
I was trying to process bytes before passing to MediaCodec. Defined nal_unit_type. I get 7, 8 and 28. I also defined startBit and endBit in the package. I tried to glue all packages starting with startBit and ending with endBit and transfer them to MediaCodec in a glued form. The result is the same - the dequeueOutputBuffer method always returns MediaCodec.INFO_TRY_AGAIN_LATER
Tell me what I missed.
The server sends the following information about the video to the SDP:
m=video 23542 RTP/AVP 97
b=TIAS:4096000
a=content:main
a=rtpmap:97 H264/90000
a=fmtp:97 profile-level-id=428028; max-fs=8192; packetization-mode=0; max-br=4096; max-fps=3000
a=sendrecv
Edit #1
For example, first received packet payload (array of unsigned byte):
27 42 00 28 95 a0 1e 00 89 f9 70 11 00 00 03 00
42 00 28 95 a0 1e 00 89 f9 70 11 00 00 03 00 01
00 28 95 a0 1e 00 89 f9 70 11 00 00 03 00 01 00
I would venture to suggest that this is a Single NAL Unit Packet. This packet has no padding.
By rfc3984/1.3 i got in first byte:
// 0 1 2 3 4 5 6 7
// +-----+---------+
// | type |
// +-----+---------+
val nal_unit_type = payload[0].toInt() and 0b0_0_0_1_1_1_1_1
nal_unit_type == 7 And I decided that this package contains Sequence Parameter Set data. Next, I want to get the decrypt SPS and get useful information from it (width and height, frame rate ...)
I got in second byte:
// 0 1 2 3 4 5 6 7
// +-+-+-----------+
// |s|e|
// +-+-+-----------+
val start_bit = payload[1].toInt() and 0b1_0_0_0_0_0_0_0 != 0
// +-+-+-----------+
val end_bit = payload[1].toInt() and 0b0_1_0_0_0_0_0_0 != 0
start_bit == false and end_bit == true
Starting from the third byte (payload[2]), I parse the SPS.
Edit #2
I was wrong when I decided that the second byte for nal_unit_type 7 or 8 is the FU header (with start and end bits). The second byte of the payload is already the first byte of the SPS. Thus, I managed to successfully decrypt the SPS and, for example, find out that the image size 1920/1080 is encrypted there (as was expected). But this has not yet helped me in any way to draw the resulting video stream to the android surface view.

Discrepancy between Java's public key representation and RFC 8410

RFC 8410 lists this as an example of a Ed25519 public key: MCowBQYDK2VwAyEAGb9ECWmEzf6FQbrBZ9w7lshQhqowtrbLDFw4rXAxZuE=
Decoding this with an ASN.1 decoder, this becomes:
30 2A
30 05
06 03 2B6570 // Algorithm Identifier
03 21 0019BF44096984CDFE8541BAC167DC3B96C85086AA30B6B6CB0C5C38AD703166E1
As expected, this matches the SubjectPublicKeyInfo definition in the RFC.
Using the Sun cryptography provider in Java 11+ I can use this code to generate an X25519 (not Ed25519 - which is the difference in the algorithm identifier below) public key:
import java.security.KeyPairGenerator;
import java.util.Base64;
public class PrintPublicKey {
public static void main(String args[]) throws Exception {
KeyPairGenerator generator = KeyPairGenerator.getInstance("X25519");
byte[] encodedPublicKey = generator.generateKeyPair().getPublic().getEncoded();
System.out.println(Base64.getEncoder().encodeToString(encodedPublicKey));
}
}
Which will output something like: MCwwBwYDK2VuBQADIQDlXKI/cMoICnQRrV+4c//viHnXMoB190/z2MX/otJQQw==
Decoding this with an ASN.1 decoder, this becomes:
30 2C
30 07
06 03 2B656E // Algorithm Identifier
05 00 // Algorithm Parameters - NULL
03 21 00E55CA23F70CA080A7411AD5FB873FFEF8879D7328075F74FF3D8C5FFA2D25043
This has an explicit NULL after the object identifier. Is this valid according to the specification? It says:
In this document, we define four new OIDs for identifying the different curve/algorithm pairs: the curves being curve25519 and curve448 and the algorithms being ECDH and EdDSA in pure mode.
For all of the OIDs, the parameters MUST be absent.
The paragraph after the one you quoted says this:
It is possible to find systems that require the parameters to be
present. This can be due to either a defect in the original 1997
syntax or a programming error where developers never got input where
this was not true. The optimal solution is to fix these systems;
where this is not possible, the problem needs to be restricted to
that subsystem and not propagated to the Internet.
So a plausible explanation for the Oracle implementation's behavior is that they want to be interoperable with old systems that require parameters. It is the kind of thing that you do to prevent big customers with large support contracts from complaining loudly that "upgrading to Java 11 broke my infrastructure".

How to generate secret key to get TOTP for HMAC SHA512 comply with RFC6238 and RFC4086?

I have to make an HTTP POST request to the URL http://example.com/test which contains the JSON string as a body part, headers "Content-Type:application/json" and "Authorization: Basic userid:password". userid is abc#example.com and password must be 10-digit time-based one time password comply with RFC6238 TOTP using HMAC-SHA-512 for the hash function.
Token shared secret should be "abc#example.comTEXT5" without double quotations.
So, to achieve above I modified the Java code of RFC6238 RC6238 TOTP Algo
To get TOTP, I converted the shared secret "abc#example.comTEXT5" to HMAC-SHA512 using online converter tool as well some codes which generate the same 128 character length HEX code
Making the request always responses that "TOTP is wrong".
I noticed that I generated the wrong secret key, so there is the wrong TOTP. So, how can I generate the correct secret key that complies HMAC-SHA512 with Java code of RFC6238 algorithm?
There is default key as seed on the algorithm:
String seed64 = "3132333435363738393031323334353637383930" +
"3132333435363738393031323334353637383930" +
"3132333435363738393031323334353637383930" +
"31323334";
How can I get such seed64 for my shared secret "abc#example.comTEXT5"?
My modified code is 10 digit TOTP
I appreciate help from everyone!
The example 64 byte seed in Appendix A of RFC 6238 is the HEX encoded version of the ASCII secret 12345678901234567890 provided in Appendix B which contains the truth table.
ASCII 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0
HEX 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30
If you want to convert your shared secret using the same pattern, you would convert abc#example.comTEXT5 to HEX in string format if you're using the example code provided in Appendix A.
This would come out to the following HEX string :
616263406578616D706C652E636F6D5445585435
To build the example 64 byte seed used for the SHA-512 hash the initial 20 bytes are repeated to make 64 bytes total to achieve an optimal key length for the SHA-512 hash.
Doing the same with your example string would produce the following seed:
String seed64 = "616263406578616D706C652E636F6D5445585435" +
"616263406578616D706C652E636F6D5445585435" +
"616263406578616D706C652E636F6D5445585435" +
"61626340";
If you use the rest of the example code to calculate the time step and request a 10 digit TOTP code, I assume it will work for you.
If you are using something like this in production, you may wish to use a more randomly generated secret.
For example, to generate a 64 byte secret for SHA-512, you could do something like:
public static String generateRawSecret(int length) {
byte[] buf = new byte[length];
new SecureRandom().nextBytes(buf);
String rawSecret = Base64.getEncoder().encodeToString(buf);
return rawSecret.substring(1, length + 1);
}
// Random 64 byte secret
String secret = generateRawSecret(64);
It looks like you've already got most of this coded, but if you're looking for some additional Java examples, the following link is a GitHub project that has a simple utility class with a bunch of tests. https://github.com/FusionAuth/fusionauth-2FA

Android BLE BluetoothAdapter.LeScanCallback scanRecord length ambiguity

I am using the example project from google (BluetoothLeGatt) to receive data from a BLE device and trying to read a specific byte within it's scanRecord obtained by the onLeScan method.
My problem is that there is missmatch between the data I am observing in the network and what I see on logs.
This is on Android 4.3 and using a Samsung Galaxy S4 to test it.
To verify that the scanRecord logs are correct on Android, I am using TI's Packet Sniffer to observe the byte stream being broadcasted by the device, and here it is:
That is 31 bytes of data being broadcasted by the device to the network, and there are no other working devices around.
02 01 1A 1A FF 4C 00 02 15 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 0C C6 64
On the other hand, Android logs claim that the data being received has the length of 62 bytes and it matches the data until the 29th[0-indexed] byte, having 0s for the rest of the data.
02-12 15:34:09.548: D/DEBUG(26801): len: 62
data:02011a1aff4c000215000000000000000000000000000000000000000cc60000000000000000000000000000000000000000000000000000000000000000
And this is the code piece I used in order to obtain the logs within the LeScanCallback method:
int len = scanRecord.length;
String scanHex = bytesToHex(scanRecord);
Log.d("DEBUG", "len: " + len + " data:" + scanHex);
The method used to convert byte array to hex representation:
private static String bytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
int v;
for ( int j = 0; j < bytes.length; j++ ) {
v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
I used a few other example projects including Dave Smith's example and RadiusNetworks' Android iBeacon Library and I ended up with the same results. I can't possibly understand why do I receive 62 bytes of data when "Packet Sniffer" shows (and I also know) that it should be 31 bytes. This would not be my main concern if I was able to read the data in the last byte correctly (I get 00 instead of 64 from Android's BluetoothAdapter). But that is not the case either.
I would appreciate any suggestions about what might potentially be the reason for this missmatch for both the data(last byte only) and the data size between what Android receives and what is actually on the network.
Your transmission is malformed, containing 31 bytes of payload data (PDU length of 37) when its internal length fields indicate it should in total contain only 30 bytes (PDU length 36).
Let's take a look at your data
02 01 1a
This is a length (2) of type codes - 01 and 1a, and good so far
1a ff 4c ...
Now we have a problem - the 1a is a length code for this field (manufacturer specific data), value of 26. Yet 27 bytes of data follow it in your case, instead of the proper 26 you have indicated you will provide.
Now, if you have a properly formed packet, you will still get a larger buffer padded with meaningless (likely uninitialized) values following the proper content, but you can simply ignore that by parsing the buffer in accordance with the field-length values and ignoring anything not accounted for in the proclaimed lengths.
But with your current malformed packet, the copying of packet data to the buffer stops at the proclaimed content size, and the unannounced extra byte never makes it into the buffer your program receives - so you see instead something random there, as with the rest of the unused length.
Probably, when you made up your all-zeroes "region UUID" (might want to rethink that) you simply typed an extra byte...

Some certificates private keys in Windows-MY not detected

Using Windows 7, JDK 6 (and 7).
I'm trying to get personal certificates stored in Windows MSCAPI key store and it's basic properties (in order to use private key for signing). However some aliases are identified not having private key (isKeyEntry == false) although it acctually has one.
Any suggestions how to deal with this "feature"?
The P12 file with certificate (already revoked) & private key having this weird "property" can be downloaded from http://download.upce.cz/terena-public.pfx. Password is "password".
KeyStore ks = KeyStore.getInstance("Windows-MY", "SunMSCAPI");
ks.load(null, null);
Enumeration<String> aliases = ks.aliases();
while (aliases.hasMoreElements()) {
String alias = (String) aliases.nextElement();
X509CertImpl certificate = (X509CertImpl)ks.getCertificate(alias);
System.out.println("Alias: " + alias);
System.out.println(" Subject: " + certificate.getSubjectDN());
System.out.println(" Issued By: " + certificate.getIssuerDN());
if (ks.isKeyEntry(alias)) {
System.out.println(" Has private key");
}
}
I imported your pfx-file into Mozilla Thunderbird and exported it as p12-file. Now I can see it through MSCAPI. There must be something in the original certificate that prevents MSCAPI to see the private key.
I compared the files and I noticed that in the original file the Key Usage section is used.
Original pfx:
Bag Attributes
localKeyID: 01 00 00 00
friendlyName: le-b6311e84-87e7-4e02-9cf6-4012518e0541
Microsoft CSP Name: Microsoft Software Key Storage Provider
Key Attributes
X509v3 Key Usage: 90
Converted p12:
Bag Attributes
friendlyName: le-b6311e84-87e7-4e02-9cf6-4012518e0541
localKeyID: 47 E4 D3 F0 75 48 9D 77 07 E9 51 A4 F1 B6 DF E9 40 80 26 7A
Key Attributes: <No Attributes>
There are more differences in the two files, but I'm not sure which one causes the unwanted behaviour.

Categories