convert STACK_OF(X509) to ASN1 stream - c++

first of all: Sorry for my bad english. I hope you can understand me.
I using OpenSSL 1.0.2 and I have some problems with it. I have a STACK_OF(X509) object with three certificates and I want to convert this stack to an ASN1 object (like OCTET STRING or ANY). Is this possible? I use an external asn.1 library and not OpenSSL-ASN1. So I need the data as unsigned char (raw binary or DER encoded).
I can convert a single certificate via i2d_X509() into DER format. This is good, but I want the complete stack. This is my goal:
myAsn1Data ::= sequence {
... -- (some ASN.1 data)
... -- (some ASN.1 data)
ANY -- contain the DER encoded STACK_OF(X509)....somehow
}
But possibly is this the right way (ASN.1 syntax):
stackOfX509 ::= SEQUENCE_Of {
TBSCertificate
}
or like this:
stackOfX509 ::= SET_OF {
ANY -- contain a DER encoded X509 certificate
}
I hope someone can help me.

People normally do one of two things for this.
1) "Cheat"! If the DER encoded representation of the certificate is available but the original schema for it is not, simply have an OCTET STRING to store the bytes.
myAsn1Data ::= SEQUENCE {
..., -- (some ASN.1 Data)
..., -- (some ASN.1 Data)
cert [2] OCTET STRING -- (the DER bytes would go in this field)
}
and the flow of your application code would be something like
myAsn1Data data = new(myAsn1Data);
data.cert = readbytesfromfile(certificatefile);
data.something = 10;
data.else = 20;
asn1encode(data, outputfile)
2) Acquire the original schema for an X509 certificate. It ought to be in here somewhere, looks like section 7.2. With this the source your ASN.1 compiler will create for you should be able to decode the certificate, allowing you to place it inside an instance of your myAsn1Data.
IMPORTS Certificate FROM <ITU's X509 Schema file>
CertificateStack ::= SEQUENCE of Certificate
myAsn1Data ::= SEQUENCE {
..., -- (some ASN.1 Data)
..., -- (some ASN.1 Data)
cert [2] CertificateStack
}
and the sequences in your application code would look something like this:
Certificate cert1 = asn1decode(certificatefile);
Certificate cert2 = asn1decode(anothercertificatefile);
Certificate cert3 = asn1decode(yetanothercertificatefile);
CertificateStack stack;
stack.push_back(cert1);
stack.push_back(cert2);
stack.push_back(cert3);
myAsn1Data data = new(myAsn1Data);
data.cert = stack;
data.something = 10;
data.else = 20;
asn1encode(data, outputfile)
This way is better because it completely defines what the 'cert' field actually is. The first way isn't quite so good if you are exchanging data with someone else because they need to be told what the cert field actually is.

Related

NEAR FunctionCall `args` field

In the near_primitives::views, the args field on the FunctionCall is represented as a String type. From the chain data model, which is transaction::Action::FunctionCall, its args field there is a `Vec.
The question is, does this args field will always content a valid JSON payload as the content? We assume the answer is probably a No since the underlying field contains pure bytes.
In which circumstances this would a valid JSON string and in which circumstances it would be a binary format?
Finally, if binary format is possible (likely), how is it possible to decode it? Is this in developers hand and could be any binary format?
See
https://github.com/near/nearcore/blob/14711926391d3ec1d23116658a295a62e77bc701/core/primitives/src/views.rs#L768
https://github.com/near/nearcore/blob/14711926391d3ec1d23116658a295a62e77bc701/core/primitives/src/transaction.rs#L113
In most cases args will be base64 encoded JSON string.
Here's an example of how we decode them on NEAR Indexer for Explorer side.
ActionView::FunctionCall {
method_name,
args,
gas,
deposit,
} => {
if let Ok(decoded_args) = base64::decode(args) {
if let Ok(mut args_json) = serde_json::from_slice(&decoded_args) {
escape_json(&mut args_json);
arguments["args_json"] = args_json;
}
}
Is this in developers hand and could be any binary format?
Yes.
Rainbow Bridge-related transactions have borsh-serialized args which are not possible to decode into JSON.
ref: https://github.com/near/near-indexer-for-explorer/blob/master/src/models/serializers.rs#L94-L103
args are not limited to any format at all, they are just binary blob. What you see in the views.rs is partially serialized data where args are expected to be in base64 encoding thus it is a String (thus, it is always base64 data there; be it JSON, Borsh-serialized data, or just raw binary blob, e.g. PNG image)

How to extract ip address from subject_alt_name field from OpenSSL certificates using API(not openssl commands) in C

My requirement is to extract ip address from openSSL certificates using OpenSSL API functions(not openSSL primitive commands).
I can use ASN1_STRING_data() to extract san field details, but how do i print the ip address from it.What is the data type of the ip address field
I am fetching common name and san field from certificates following the below code flow.I am able to fetch the common name, but having troubles with the SAN field
Using openssl api for C , was able to fetch the common name field but not the SAN ip field
common_name(X509* server_cert)
{
X509_NAME *subject_name = X509_get_subject_name((X509 *)server_cert);
int common_name_loc = X509_NAME_get_index_by_NID(subject_name, NID_commonName, -1);
X509_NAME_ENTRY *common_name_entry =
X509_NAME_get_entry(X509_get_subject_name((X509 *) server_cert), common_name_loc);
ASN1_STRING *common_name_asn1 = X509_NAME_ENTRY_get_data(common_name_entry);
char *common_name_str = (char *) ASN1_STRING_data(common_name_asn1);
}
san_field(X509 *cert)
{
STACK_OF(GENERAL_NAME) *san_names = NULL;
// Try to extract the names within the SAN extension from the certificate
san_names = static_cast<STACK_OF(GENERAL_NAME)*>(X509_get_ext_d2i((X509 *)cert, NID_subject_alt_name, NULL, NULL));
san_names_nb = sk_GENERAL_NAME_num(san_names);
// Check each name within the extension
for (i=0; i<san_names_nb; i++)
{
const GENERAL_NAME *current_name = sk_GENERAL_NAME_value(san_names, i);
if (current_name->type == GEN_IPADD)
{
const char* ip_addrezz = reinterpret_cast<char*>
(ASN1_STRING_data(current_name->d.iPAddress));
print ---------->ip_addrezz //issue here
}
}
}
How to extract SAN ip field from certificate
How to print the ip address extracted from SAN field of certificate/what is the data type of the ip field
Am i going in correct direction
As i recently also stumbled upon this and i would like to document the answer that suited best for me (i hope i got the point of this question right):
RFC5280 - Subject Alternative Name states, that iPAddress is
stored in the octet string in "network byte order"
When the subjectAltName extension contains an iPAddress, the address
MUST be stored in the octet string in "network byte order", as
specified in [RFC791]. The least significant bit (LSB) of each octet
is the LSB of the corresponding byte in the network address. For IP
version 4, as specified in [RFC791], the octet string MUST contain
exactly four octets. For IP version 6, as specified in
[RFC2460], the octet string MUST contain exactly sixteen octets.
Which in turn means, for an IPv4 address, you might use something like
std::stringstream ip{};
ip << (int)ip_addrezz[0] << '.' << (int)ip_addrezz[1] << '.' << (int)ip_addrezz[2] << '.' << (int)ip_addrezz[3]
return ip.str();
to print it.
I also found this post really helpful (the code above is copied from there).

How to parse SubjectDirectoryAttributes Extension with OpenSSL?

How can I read the X509 Certificate Extension: Subject Directory Attributes with OpenSSL in C++?
My Certificate contains the SubjectDirectoryAttributes-Extension with the following Attributes:
OID : Value
-------------------------------------------------------------------
(1.3.6.1.5.5.7.9.4) countryOfCitizenship : DE
(1.3.6.1.5.5.7.9.3) gender : F
(1.3.6.1.5.5.7.9.1) dateOfBirth : 1971-10-14 12:00:00 UTC
(1.3.6.1.5.5.7.9.2) placeOfBirth : Darmstadt
So i want to get these pairs of OID and Value.
I found no Struct like SUBJECT_DIRECTORY_ATTRIBUTES in the Source-Code I can use. I got the Extension this way:
int loc = X509_get_ext_by_NID(certificate, NID_subject_directory_attributes, -1);
X509_EXTENSION *ex = X509_get_ext(certificate, loc);
But how can I get then all the data, which means all the OIDs and Values to the OIDs? The ASN.1 Structure is:
SubjectDirectoryAttributes ::= Attributes
Attributes ::= SEQUENCE SIZE (1..MAX) OF Attribute
Attribute ::= SEQUENCE
{
type AttributeType
values SET OF AttributeValue
}
AttributeType ::= OBJECT IDENTIFIER
AttributeValue ::= ANY DEFINED BY AttributeType
I found out that I get a custom extension with: X509_EXTENSION_get_object(ex) and that the OpenSSL-Type X509_NAME_ENTRY is the equvivalent to the ASN.1-Structure Attribute resp. AttributeTypeAndValue.
So i tried to cast the result of X509_EXTENSION_get_data(ex) to a STACK_OF(X509_NAME_ENTRY) and to X509_NAME. But X509_NAME is the same as STACK_OF(X509_NAME_ENTRY).
Then I tried to get the number of attributes by calling the sk_X509_NAME_ENTRY_num() function on the STACK_OF(X509_NAME_ENTRY) resp. X509_NAME.entries, but I got not the right number.
I expect to get the number 3 or 4 (don't know the exactly internal counting - but the example cert contains 4 Attributes, so the output should be 3 or 4 depending if the counting will start at 0 or 1).
But instead of 3 or 4 I got a much larger number like 34335029 and this number is different every time I run the code. So I think there is a problem with the casting or I did not choose the right Data-Type(s).
I'm using OpenSSL 1.0.2j.
So what's wrong and how can I fix it?
Here a short excerpt of my code:
X509_EXTENSION *ex = ....
STACK_OF(X509_NAME_ENTRY) *st = (STACK_OF(X509_NAME_ENTRY)*) X509_EXTENSION_get_data(ex);
printf(sk_X509_NAME_ENTRY_num(st));
// or alternative
X509_Name *name = (X509_Name*) X509_EXTENSION_get_data(ex);
printf(sk_X509_NAME_ENTRY_num(name.entries));
Here I append the certificate if you need it. It's from the RFC specification:
-----BEGIN CERTIFICATE-----
MIIDEDCCAnmgAwIBAgIESZYC0jANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQGEwJE
RTE5MDcGA1UECgwwR01EIC0gRm9yc2NodW5nc3plbnRydW0gSW5mb3JtYXRpb25z
dGVjaG5payBHbWJIMB4XDTA0MDIwMTEwMDAwMFoXDTA4MDIwMTEwMDAwMFowZTEL
MAkGA1UEBhMCREUxNzA1BgNVBAoMLkdNRCBGb3JzY2h1bmdzemVudHJ1bSBJbmZv
cm1hdGlvbnN0ZWNobmlrIEdtYkgxHTAMBgNVBCoMBVBldHJhMA0GA1UEBAwGQmFy
emluMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDc50zVodVa6wHPXswg88P8
p4fPy1caIaqKIK1d/wFRMN5yTl7T+VOS57sWxKcdDzGzqZJqjwjqAP3DqPK7AW3s
o7lBG6JZmiqMtlXG3+olv+3cc7WU+qDv5ZXGEqauW4x/DKGc7E/nq2BUZ2hLsjh9
Xy9+vbw+8KYE9rQEARdpJQIDAQABo4HpMIHmMGQGA1UdCQRdMFswEAYIKwYBBQUH
CQQxBBMCREUwDwYIKwYBBQUHCQMxAxMBRjAdBggrBgEFBQcJATERGA8xOTcxMTAx
NDEyMDAwMFowFwYIKwYBBQUHCQIxCwwJRGFybXN0YWR0MA4GA1UdDwEB/wQEAwIG
QDASBgNVHSAECzAJMAcGBSskCAEBMB8GA1UdIwQYMBaAFAABAgMEBQYHCAkKCwwN
Dg/+3LqYMDkGCCsGAQUFBwEDBC0wKzApBggrBgEFBQcLAjAdMBuBGW11bmljaXBh
bGl0eUBkYXJtc3RhZHQuZGUwDQYJKoZIhvcNAQEFBQADgYEAj4yAu7LYa3X04h+C
7+DyD2xViJCm5zEYg1m5x4znHJIMZsYAU/vJJIJQkPKVsIgm6vP/H1kXyAu0g2Ep
z+VWPnhZK1uw+ay1KRXw8rw2mR8hQ2Ug6QZHYdky2HH3H/69rWSPp888G8CW8RLU
uIKzn+GhapCuGoC4qWdlGLWqfpc=
-----END CERTIFICATE-----
Since OpenSSL has no direct support in the crypto libary there is no built in code for parsing this extension. I have either to wait for official support or implement the whole thing by myself.

Regular Expression to detect private and public RSA keys

I've searched over the internet but with no results,
There is any pattern (to be implemented in regex) to detect RSA private or public keys ?
(not included strings such as ---- Public RSA key-- or "ssh rsa")
I'm stuck after create base64 regex
var re = regexp.MustCompile(`(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3})=`)
Thanks
Get pem formatted block
If your document contains not only PEM formatted block than Decode function from encoding/pem package will be helpful:
Decode will find the next PEM formatted block (certificate, private key etc) in the input. It returns that block and the remainder of the input. If no PEM data is found, p is nil and the whole of the input is returned in rest.
Parse key and check for rsa conformity
Go contains package named crypto to do such things like parsing keys and certifies. For purpose of parsing public keys provided function ParsePKIXPublicKey:
Supported key types include RSA, DSA, and ECDSA. Unknown key types result in an error.
On success, pub will be of type *rsa.PublicKey, *dsa.PublicKey, or *ecdsa.PublicKey.
On return you obtain concrete type which is easy to assert with type switch (idiomatic way to determine type of variable):
Example:
// There is a key
const pubPEM = `MIICIjANBgkqhkiG9...`
// Ignore the rest of document
block, _ := pem.Decode([]byte(pubPEM))
if block == nil {
log.Fatal("The document doesn't contain PEM blocks.")
}
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
log.Fatal("The block is not a DER encoded public key.")
}
switch pub := pub.(type) {
case *rsa.PublicKey:
fmt.Println("pub is of type RSA:", pub)
default:
log.Fatal("The key is not RSA encripted.")
}

Authenticating DotNetNuke Users in ColdFusion

Is there any way to authenticate users from other web apps using the DNN logins?
We have a main site that is using DNN and user logins are stored in the asp net membership table. From what I have been reading, the passwords are encrypted using the machine key and then salted. I see where this info is, but can't seem to encrypt passwords correctly using this method.
I'm trying with a Coldfusion web application on the same server where our DNN site is, but it doesn't want to work. You'd think it would be strait forward with the ColdFusion encryption function:
Encrypt(passwordstring, key [, algorithm, encoding, IVorSalt, iterations])
No matter what I try, I never get a matching value.
Any help, insight or pointing me in the right direction would be greatly appreciated!
(Edit: Original answer did not work in all cases. Substantially revised ...)
From what I have read, DNN uses an "SHA1" hash by default. The thread #barnyr posted shows it simply hashes the concatenated salt and password, but with a few twists.
DNN uses UTF-16LE to extract the password bytes, rather than CF's typical UTF-8.
It also extracts the salt and password bytes separately, which may produce different results than just decoding everything as a single string, which is what hash() does. (See demo below)
Given that CF9's Hash function does not accept binary (supported in CF11), I do not think it is possible to duplicate the results with native CF functions alone. Instead I would suggest decoding the strings into binary, then using java directly:
Code:
<cfscript>
thePassword = "DT!#12";
base64Salt = "+muo6gAmjvvyy5doTdjyaA==";
// extract bytes of the salt and password
saltBytes = binaryDecode(base64Salt, "base64");
passBytes = charsetDecode(thePassword, "UTF-16LE" );
// next combine the bytes. note, the returned arrays are immutable,
// so we cannot use the standard CF tricks to merge them
ArrayUtils = createObject("java", "org.apache.commons.lang.ArrayUtils");
dataBytes = ArrayUtils.addAll( saltBytes, passBytes );
// hash binary using java
MessageDigest = createObject("java", "java.security.MessageDigest").getInstance("SHA-1");
MessageDigest.update(dataBytes);
theBase64Hash = binaryEncode(MessageDigest.digest(), "base64");
WriteOutput("theBase64Hash= "& theBase64Hash &"<br/>");
</cfscript>
Demo of Differences:
<cfscript>
theEncoding = "UTF-16LE";
thePassword = "DT!#12";
base64Salt = "+muo6gAmjvvyy5doTdjyaA==";
// extract the bytes SEPARATELY
saltBytes = binaryDecode(base64Salt, "base64");
passBytes = charsetDecode(thePassword, theEncoding );
ArrayUtils = createObject("java", "org.apache.commons.lang.ArrayUtils");
separateBytes = ArrayUtils.addAll( saltBytes, passBytes );
// concatenate first, THEN extract the bytes
theSalt = charsetEncode( binaryDecode(base64Salt, "base64"), theEncoding );
concatenatedBytes = charsetDecode( theSalt & thePassword, theEncoding );
// these are the raw bytes BEFORE hashing
WriteOutput("separateBytes= "& arrayToList(separateBytes, "|") &"<br>");
WriteOutput("concatenatedBytes"& arrayToList(concatenatedBytes, "|") );
</cfscript>
Results:
separateBytes = -6|107|-88|-22|0|38|-114|-5|-14|-53|-105|104|77|-40|-14|104|68|0|84|0|33|0|64|0|49|0|50|0
concatenatedBytes = -6|107|-88|-22|0|38|-114|-5|-14|-53|-105|104|-3|-1|68|0|84|0|33|0|64|0|49|0|50|0
Most likely the password is not encrypted, it is hashed. Hashing is different from encrypting, because it is not reversible.
You would not use ColdFusion's encrypt() function for this, you would use its hash() function.
So the questions you'll need to answer to figure out how to hash the passwords in CF to be able to auth against the DNN users are:
What algorithm is DNN using to hash the passwords?
How is the salt being used with the password prior to hashing?
Is DNN iterating over the hash X number of times to improve security?
All of those questions must be answered to determine how CF must use the hash() function in combination with the salt and user-submitted passwords.
I'll make some assumptions to provide an answer.
If we assume that noiteration is being done and that the salt is simply being appended to the password prior to using SHA1 to hash the password, then you'd be able to reproduce the hash digest like this:
<cfset hashDigest = hash(FORM.usersubmittedPassword & saltFromDB, "SHA1") />
(Posting a new response to keep the "encrypted" process separate from "hashing")
For "encrypted" keys, the DNN side uses the standard algorithms ie DES, 3DES or AES - depending on your machineKey settings. But with a few differences you need to match in your CF code. Without knowing your actual settings, I will assume you are using the default 3DES for now.
Data To Encrypt
The encrypted value is a combination of the salt and password. But as with hashing, DNN uses UTF-16LE. Unfortunately, ColdFusion's Encrypt() function always assumes UTF-8, which will produce a very different result. So you need to use the EncryptBinary function instead.
// sample valus
plainPassword = "password12345";
base64Salt = "x7le6CBSEvsFeqklvLbMUw==";
hexDecryptKey = "303132333435363738393031323334353637383930313233";
// first extract the bytes of the salt and password
saltBytes = binaryDecode(base64Salt, "base64");
passBytes = charsetDecode(plainPassword, "UTF-16LE" );
// next combine the bytes. note, the returned arrays are immutable,
// so we cannot use the standard CF tricks to merge them
ArrayUtils = createObject("java", "org.apache.commons.lang.ArrayUtils");
dataBytes = ArrayUtils.addAll( saltBytes, passBytes );
Encryption Algorithm
With block ciphers, ColdFusion defaults to ECB mode. (See Strong Encryption in ColdFusion) Whereas .NET defaults to CBC mode, which requires an additional IV value. So you must adjust your CF code to match.
// convert DNN hex key to base64 for ColdFusion
base64Key = binaryEncode(binaryDecode( hexDecryptKey, "hex"), "base64");
// create an IV and intialize it with all zeroes
// block size: 16 => AES, 8=> DES or TripleDES
blockSize = 8;
iv = javacast("byte[]", listToArray(repeatString("0,", blocksize)));
// encrypt using CBC mode
bytes = encryptBinary(dataBytes, base64Key, "DESede/CBC/PKCS5Padding", iv);
// result: WBAnoV+7cLVI95LwVQhtysHb5/pjqVG35nP5Zdu7T/Cn94Sd8v1Vk9zpjQSFGSkv
WriteOutput("encrypted password="& binaryEncode( bytes, "base64" ));