SSH SubjectPublicKeyInfo from modulus and exponent - ruby

I'm extracting the modulus and exponent from a public SSH key with the goal of generating a PEM public key. Here is my code so far:
require "base64"
require "openssl"
def unpacked_byte_array(ssh_type, encoded_key)
prefix = [7].pack("N") + ssh_type
decoded = Base64.decode64(encoded_key)
# Base64 decoding is too permissive, so we should validate if encoding is correct
unless Base64.encode64(decoded).gsub("\n", "") == encoded_key && decoded.slice!(0, prefix.length) == prefix
raise PublicKeyError, "validation error"
end
data = []
until decoded.empty?
front = decoded.slice!(0,4)
size = front.unpack("N").first
segment = decoded.slice!(0, size)
unless front.length == 4 && segment.length == size
raise PublicKeyError, "byte array too short"
end
data << OpenSSL::BN.new(segment, 2)
end
return data
end
module OpenSSL
module PKey
class RSA
def self.new_from_parameters(n, e)
a = self.new # self.new(64) for ruby < 1.8.2
a.n = n # converted to OpenSSL::BN automatically
a.e = e
a
end
end
end
end
e, n = unpacked_byte_array('ssh-rsa', 'AAAAB3NzaC1yc2EAAAABIwAAAQEA3RC8whKGFx+b7BMTFtnIWl6t/qyvOvnuqIrMNI9J8+1sEYv8Y/pJRh0vAe2RaSKAgB2hyzXwSJ1Fh+ooraUAJ+q7P2gg2kQF1nCFeGVjtV9m4ZrV5kZARcQMhp0Bp67tPo2TCtnthPYZS/YQG6u/6Aco1XZjPvuKujAQMGSgqNskhKBO9zfhhkAMIcKVryjKYHDfqbDUCCSNzlwFLts3nJ0Hfno6Hz+XxuBIfKOGjHfbzFyUQ7smYnzF23jFs4XhvnjmIGQJcZT4kQAsRwQubyuyDuqmQXqa+2SuQfkKTaPOlVqyuEWJdG2weIF8g3YP12czsBgNppz3jsnhEgstnQ==')
rsa = OpenSSL::PKey::RSA.new_from_parameters(n, e)
puts rsa
The goal is to have a pure Ruby implementation of what ssh-keygen -f <file> -e -m pem does.
Now, comparing the results, they look very similar, but my code returns a few more bytes at the beginning of the key:
$ ssh-keygen -f ~/.ssh/id_rsa_perso.pub -e -m pem
-----BEGIN RSA PUBLIC KEY-----
MIIBCAKCAQEA3RC8whKGFx+b7BMTFtnIWl6t/qyvOvnuqIrMNI9J8+1sEYv8Y/pJ
Rh0vAe2RaSKAgB2hyzXwSJ1Fh+ooraUAJ+q7P2gg2kQF1nCFeGVjtV9m4ZrV5kZA
RcQMhp0Bp67tPo2TCtnthPYZS/YQG6u/6Aco1XZjPvuKujAQMGSgqNskhKBO9zfh
hkAMIcKVryjKYHDfqbDUCCSNzlwFLts3nJ0Hfno6Hz+XxuBIfKOGjHfbzFyUQ7sm
YnzF23jFs4XhvnjmIGQJcZT4kQAsRwQubyuyDuqmQXqa+2SuQfkKTaPOlVqyuEWJ
dG2weIF8g3YP12czsBgNppz3jsnhEgstnQIBIw==
-----END RSA PUBLIC KEY-----
$ ruby ssh2x509.rb
-----BEGIN PUBLIC KEY-----
MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEA3RC8whKGFx+b7BMTFtnI
Wl6t/qyvOvnuqIrMNI9J8+1sEYv8Y/pJRh0vAe2RaSKAgB2hyzXwSJ1Fh+ooraUA
J+q7P2gg2kQF1nCFeGVjtV9m4ZrV5kZARcQMhp0Bp67tPo2TCtnthPYZS/YQG6u/
6Aco1XZjPvuKujAQMGSgqNskhKBO9zfhhkAMIcKVryjKYHDfqbDUCCSNzlwFLts3
nJ0Hfno6Hz+XxuBIfKOGjHfbzFyUQ7smYnzF23jFs4XhvnjmIGQJcZT4kQAsRwQu
byuyDuqmQXqa+2SuQfkKTaPOlVqyuEWJdG2weIF8g3YP12czsBgNppz3jsnhEgst
nQIBIw==
-----END PUBLIC KEY-----
Notice my output has the content of the ssh-keygen output, but with MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0A prepended.
What could cause these extra bytes, and how could I get the proper result?

It seems the output format for RSA keys in Ruby OpenSSL was changed in 1.9.3 from PKCS#1 (used by OpenSSH) to X509 (used by OpenSSL post 1.9.3):
https://redmine.ruby-lang.org/issues/4421
What is suggested in this bug report is to emulate the PKCS#1 with:
ary = [OpenSSL::ASN1::Integer.new(n), OpenSSL::ASN1::Integer.new(e)]
pub_key = OpenSSL::ASN1::Sequence.new(ary)
base64 = Base64.encode64(pub_key.to_der)
#This is the equivalent to the PKCS#1 encoding used before 1.9.3
pem = "-----BEGIN RSA PUBLIC KEY-----\n#{base64}-----END RSA PUBLIC KEY-----"
The monkey patching of OpenSSL::PKey::RSA is thus not necessary.

To solve this problem, you can analyze ASN1 structure.
For you output, it is
SEQUENCE(2 elem)
SEQUENCE(2 elem)
OBJECT IDENTIFIER1.2.840.113549.1.1.1
NULL
BIT STRING(1 elem)
SEQUENCE(2 elem)
INTEGER(2048 bit) 279069188856447290054297383130027286257044344789969750715307012565210…
INTEGER35
For ssh output, it is
SEQUENCE(2 elem)
INTEGER(2048 bit) 279069188856447290054297383130027286257044344789969750715307012565210…
INTEGER35
What does this mean? It means your RSA key is structured differently. In SSH, it just contains sequence of 2048 bit integer. Whereas, in your case, it also carries object identification.
Solution? Remove those starting bits which you can calculate by analyzing ASN1 structure.
Or analyze by hexdump that how many bytes are to be removed from your RSA public key.
Your RSA public key:
30 82 01 20 30 0D 06 09 2A 86 48 86 F7 0D 01 01
01 05 00 03 82 01 0D 00 **30 82 01 08 02 82 01 01
00 DD 10 BC C2** 12 86 17 1F 9B EC 13 13 16 D9 C8
5A 5E AD FE AC AF 3A F9 EE A8 8A CC 34 8F 49 F3
ED 6C 11 8B FC 63 FA 49 46 1D 2F 01 ED 91 69 22
80 80 1D A1 CB 35 F0 48 9D 45 87 EA 28 AD A5 00
27 EA BB 3F 68 20 DA 44 05 D6 70 85 78 65 63 B5
… skipping 160 bytes …
0F D7 67 33 B0 18 0D A6 9C F7 8E C9 E1 12 0B 2D
9D 02 01 23
SSH RSA public key
**30 82 01 08 02 82 01 01 00 DD 10 BC C2** 12 86 17
1F 9B EC 13 13 16 D9 C8 5A 5E AD FE AC AF 3A F9
EE A8 8A CC 34 8F 49 F3 ED 6C 11 8B FC 63 FA 49
46 1D 2F 01 ED 91 69 22 80 80 1D A1 CB 35 F0 48
9D 45 87 EA 28 AD A5 00 27 EA BB 3F 68 20 DA 44
… skipping 160 bytes …
74 6D B0 78 81 7C 83 76 0F D7 67 33 B0 18 0D A6
9C F7 8E C9 E1 12 0B 2D 9D 02 01 23
By analyzing this, you can see that you have to remove these:
30 82 01 20 30 0D 06 09 2A 86 48 86 F7 0D 01 01
01 05 00 03 82 01 0D 00
Means 24 bytes. Remove 24 bytes from your key.
Or you can use ASN1 parser and just extract sequence.

Related

In standard RDP security, where the modulus coming from?

I'm currently working on old system that uses RDP. According to 4.1.4 Server MCS Connect Response PDU with GCC Conference Create Response described in [MS-RDPBCGR], packet is containing modulus, which should be part of RSA key. And I need to know where this came from because I need to decrypt some RDP packets stored as log.
First thing I've done is looking up certificates by using mmc. But there was no certificate matching with modulus. Even if I issued new self-signed certificate, there was no luck. Modulus is not changing by it.
More specifically, this is response packet from testing server(VM) containing modulus.
0000: 03 00 02 15 02 f0 80 7f 66 82 02 09 0a 01 00 02 | ......f......
0016: 01 00 30 1a 02 01 22 02 01 03 02 01 00 02 01 01 | ..0...".........
0032: 02 01 00 02 01 01 02 03 00 ff f8 02 01 02 04 82 | .............
0048: 01 e3 00 05 00 14 7c 00 01 2a 14 76 0a 01 01 00 | .....|..*.v....
0064: 01 c0 00 4d 63 44 6e 81 cc 01 0c 10 00 0c 00 08 | ..McDn.......
0080: 00 00 00 00 00 04 00 00 00 03 0c 10 00 eb 03 04 | ...............
0096: 00 ec 03 ed 03 ee 03 ef 03 02 0c ac 01 02 00 00 | ...........
0112: 00 02 00 00 00 20 00 00 00 78 01 00 00 bb e4 de | ..... ...x...
0128: 58 1a 05 8f 26 89 f8 94 0b 88 d4 79 d4 00 ac bf | X..&.y.
0144: e0 07 72 3a e5 9b 17 7f 17 d6 18 92 7f 01 00 00 | .r:........
0160: 00 01 00 00 00 01 00 00 00 06 00 1c 01 52 53 41 | .............RSA
0176: 31 08 01 00 00 00 08 00 00 ff 00 00 00 01 00 01 | 1..............
0192: 00 2d 13 bc 1d a9 5b c8 60 9b be 66 61 ab 09 13 | .-..[`fa..
0208: 4e 0a 1f 64 27 72 df 92 18 42 ea 2c 05 5d 0d a7 | N..d'r..B,.].
0224: f7 06 51 5d 22 2e 4a fa 03 c5 8d 52 47 7c fa 13 | .Q]".J..RG|.
0240: ec dd bb 81 15 50 4b b3 f0 7b e4 75 0e e6 0d b5 | ..PK{u..
0256: ab d2 4a 9c ab f6 8c 83 a3 53 0b 87 b1 07 fc 0f | JS...
0272: 29 12 f4 c8 18 fb 9f 6d 29 10 34 af 34 d0 ca 8d | )..m).44.
0288: 48 a9 2e 9e 85 9a 39 d6 6c be cb f3 36 75 60 a5 | H.9l6u`
0304: 56 a5 a3 f5 b0 6f af c3 8e 5b 03 11 e4 27 27 bf | Vo.[..''
0320: a0 05 51 aa f1 8d 84 11 53 43 59 b8 83 4f f2 2d | .Q.SCYO-
0336: 40 44 b1 f9 5a 5b e6 2d 32 e4 d8 ef 2a 5a f8 01 | #DZ[-2*Z.
0352: 08 7a 68 a0 05 e2 5b fe 50 b5 38 cd a6 f0 ef e0 | .zh.[P8.
0368: c4 6f 4e f3 f1 9d 0a 89 ce 79 4e 3d 6f e3 a2 b3 | oN.yN=o.
0384: c7 fd dc b2 d8 c6 76 e8 79 67 ca fe 71 5d a5 3d | .vygq]=
0400: d3 40 c4 a4 28 5c 11 b7 2a 51 cd 65 e4 5f fc 2a | #.(\.*Qe_*
0416: bf 4c b1 e0 96 89 05 4b c6 72 1a 62 eb a2 51 0d | L.Kr.bQ.
0432: 45 2f 23 27 67 0e a8 c6 12 ed 81 ee 09 58 10 02 | E/#'g...X..
0448: b2 00 00 00 00 00 00 00 00 08 00 48 00 e9 95 02 | ..........H..
0464: 48 e7 84 d6 fc 60 cd 29 b2 91 7c f4 e8 b4 36 5d | H`)|6]
0480: e5 5e b4 90 d4 d4 5d 6a a1 42 69 c6 4e 5c 87 f2 | ^]jBiN\
0496: 0a cd 86 f5 64 e3 4d 61 60 0a 17 c2 f8 94 93 83 | ..dMa`..
0512: cf 23 7d c4 a3 07 ad f0 b6 bc 1a b1 00 00 00 00 | #}.......
0528: 00 00 00 00 00 | .....
Public exponent is 01 00 01 00, modulus is 2d 13 bc 1d ... 58 10 02 b2 with additional 8 bytes of zero-padding.
After that, if I know what private exponent is, then I can decrypt Client Random and generate session key.
But as I've mentioned, I can't find where modulus is coming from. How can I obtain RSA key(or certificate, so I can use Mimikatz) for it?
Edit
I found there is Proprietary Certificate. It seems this is what I need to find, but I still don't know where it is.
Edit: I came across the Proprietary Certificate, but where is private key?
It was located at registry HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\RCM and is just public key BLOB. Still need to find private key...
Currently I'm looking into registry key Secrets under RCM, but I don't know what are these values right now.
I'm closing this because I found public key BLOB at HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\RCM\Certificate from registry though I don't know what private key is.

Curl POST request in Bash removing characters in API call

I am trying to post a public key from a server with Bash to Github as part of an automation set-up. I am using cURL for that like so:
# Make API call to Github
api_token="some string"
pub_key="$(cat /home/${project_name}/.ssh/id_rsa.pub)"
echo $pub_key
curl -H "Authorization: token ${api_token}" -H "Content-Type: application/json" -X POST -d '{"title":"'"$project_name"'","key":"'"$pub_key"'"}' https://api.github.com/user/keys
As you can see I echo the pub_key just to make sure its getting it correctly, this is the output and the result of the API call to Github:
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDi62x5maR2U42+asddDSF322dsdkjTNeG69QvV3crOeDgjiZZJTCwqoxkk9lDbfkfycS6QBazA8cPv4scxL1K1bWgXQ6p8/9TWP89/oUJcf+C9+bMzIFmJ6jOGA2ikA0+K6l7Gr4Y7SZR9UuctawFR56vFqWj9YEW7JhBQEVES9TNb+WJLZ6QPwl+PaTOt/6QXIvrnh0ffI5uuTkMg1m7XGMNuTnBnHYa2OQ0GIfL0zG8CEqLWch4AkP2gkBOFH3LnIwucS00ii9xpPVBLRv5O5WCHM9m6A7RtHtKyELu5Z6IOtLVHC6SRPnVdUaw4oEmt3aekqEEnXkq4Jom8arpiULWCYB9d5C4x6CGRrKqophHAfumoQFFh6GMtNrDLcVGUXmIa8qapOQNvsSzcDeVkyCbNu6RlurwyWYG8MH48XCrFDU3L+hmYptGEARgGd9IZSctMng/elUOIz1DL3ZGH43flMelXEZ8Umy8tAkat7/T8Yuu9tU8N8DKqKV16s= stackoverflowtest#rasenberg
{
"id": 46506612,
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDi62x5maR2U42+asddDSF322dsdkjTNeG69QvV3crOeDgjiZZJTCwqoxkk9lDbfkfycS6QBazA8cPv4scxL1K1bWgXQ6p8/9TWP89/oUJcf+C9+bMzIFmJ6jOGA2ikA0+K6l7Gr4Y7SZR9UuctawFR56vFqWj9YEW7JhBQEVES9TNb+WJLZ6QPwl+PaTOt/6QXIvrnh0ffI5uuTkMg1m7XGMNuTnBnHYa2OQ0GIfL0zG8CEqLWch4AkP2gkBOFH3LnIwucS00ii9xpPVBLRv5O5WCHM9m6A7RtHtKyELu5Z6IOtLVHC6SRPnVdUaw4oEmt3aekqEEnXkq4Jom8arpiULWCYB9d5C4x6CGRrKqophHAfumoQFFh6GMtNrDLcVGUXmIa8qapOQNvsSzcDeVkyCbNu6RlurwyWYG8MH48XCrFDU3L+hmYptGEARgGd9IZSctMng/elUOIz1DL3ZGH43flMelXEZ8Umy8tAkat7/T8Yuu9tU8N8DKqKV16s=",
"url": "https://api.github.com/user/keys/46506612",
"title": "stackoverflowtest",
"verified": true,
"created_at": "2020-09-27T04:23:30Z",
"read_only": false
}
As you can see in the API call, Curl cuts of the = stackoverflowtest#rasenberg part at the end, and therefore I post an invalid pub key to Github, resulting it in not working. What is going wrong?
As https://stackoverflow.com/users/3266847/benjamin-w commented (!), the comment portion of an OpenSSH-format pubkey is optional and not needed, and was almost certainly removed by github (after receipt) not by curl. However, your key is in fact invalid and I'm a bit surprised github considers it verified.
$ printf AAAAB3NzaC1yc2EAAAADAQABAAABgQDi62x5maR2U42+asddDSF322dsdkjTNeG69QvV3crOeDgjiZZJTCwqoxkk9lDbfkfycS6QBazA8cPv4scxL1K1bWgXQ6p8/9TWP89/oUJcf+C9+bMzIFmJ6jOGA2ikA0+K6l7Gr4Y7SZR9UuctawFR56vFqWj9YEW7JhBQEVES9TNb+WJLZ6QPwl+PaTOt/6QXIvrnh0ffI5uuTkMg1m7XGMNuTnBnHYa2OQ0GIfL0zG8CEqLWch4AkP2gkBOFH3LnIwucS00ii9xpPVBLRv5O5WCHM9m6A7RtHtKyELu5Z6IOtLVHC6SRPnVdUaw4oEmt3aekqEEnXkq4Jom8arpiULWCYB9d5C4x6CGRrKqophHAfumoQFFh6GMtNrDLcVGUXmIa8qapOQNvsSzcDeVkyCbNu6RlurwyWYG8MH48XCrFDU3L+hmYptGEARgGd9IZSctMng/elUOIz1DL3ZGH43flMelXEZ8Umy8tAkat7/T8Yuu9tU8N8DKqKV16s= |openssl base64 -d -A|od -Ax -tx1
000000 00 00 00 07 73 73 68 2d 72 73 61 00 00 00 03 01
000010 00 01 00 00 01 81 00 e2 eb 6c 79 99 a4 76 53 8d
000020 be 6a c7 5d 0d 21 77 db 67 6c 76 48 d3 35 e1 ba
000030 f5 0b d5 dd ca ce 78 38 23 89 96 49 4c 2c 2a a3
000040 19 24 f6 50 db 7e 47 f2 71 2e 90 05 ac c0 f1 c3
000050 ef e2 c7 31 2f 52 b5 6d 68 17 43 aa 7c ff d4 d6
000060 3f cf 7f a1 42 5c 7f e0 bd f9 b3 33 20 59 89 ea
000070 33 86 03 68 a4 03 4f 8a ea 5e c6 af 86 3b 49 94
000080 7d 52 e7 2d 6b 01 51 e7 ab c5 a9 68 fd 60 45 bb
000090 26 10 50 11 51 12 f5 33 5b f9 62 4b 67 a4 0f c2
0000a0 5f 8f 69 33 ad ff a4 17 22 fa e7 87 47 df 23 9b
0000b0 ae 4e 43 20 d6 6e d7 18 c3 6e 4e 70 67 1d 86 b6
0000c0 39 0d 06 21 f2 f4 cc 6f 02 12 a2 d6 72 1e 00 90
0000d0 fd a0 90 13 85 1f 72 e7 23 0b 9c 4b 4d 22 8b dc
0000e0 69 3d 50 4b 46 fe 4e e5 60 87 33 d9 ba 03 b4 6d
0000f0 1e d2 b2 10 bb b9 67 a2 0e b4 b5 47 0b a4 91 3e
000100 75 5d 51 ac 38 a0 49 ad dd a7 a4 a8 41 27 5e 4a
000110 b8 26 89 bc 6a ba 62 50 b5 82 60 1f 5d e4 2e 31
000120 e8 21 91 ac aa a8 a6 11 c0 7e e9 a8 40 51 61 e8
000130 63 2d 36 b0 cb 71 51 94 5e 62 1a f2 a6 a9 39 03
000140 6f b1 2c dc 0d e5 64 c8 26 cd bb a4 65 ba bc 32
000150 59 81 bc 30 7e 3c 5c 2a c5 0d 4d cb fa 19 98 a6
000160 d1 84 01 18 06 77 d2 19 49 cb 4c 9e 0f de 95 43
000170 88 cf 50 cb dd 91 87 e3 77 e5 31 e9 57 11 9f 14
000180 9b 2f 2d 02 46 ad ef f4 fc 62 eb bd b5 4f 0d f0
000190 32 aa 29 5d 7a
000195
The length of n, 00 00 01 81 at byte offsets 0x12-0x15, would correspond to a 3072-bit RSA key (with the sign byte required by SSH mpint) but implies the total length of the blob (after base64 decoding, or before encoding) should be 0x197 and instead it's actually 0x195, making it invalid and unusable. Check whatever program or process you used to create this key; there's a bug somewhere.

Authentication Error: DESfire against SAM with 3DES algorithm

I can't finish the authentication phase.
What I am using:
SAM module by NXP
Mifare Desfire PICC
I am following the next steps:
Get PICC SerialNumber (or UID) with GetVersion.
GET VERSION:
Tx: 90 60 00 00 00
Rx: 04 01 01 00 02 18 05 91 AF
GET VERSION 2:
Tx: 90 AF 00 00 00 00
Rx: 04 01 01 00 06 18 05 91 AF
GET VERSION 3:
Tx: 90 AF 00 00 00 00
Rx: 04 65 41 49 65 1B 80 8E 65 58 51 30 46 07 91 00
Get encrypted(RndB) from PICC.
Tx: 90 0A 00 00 01 00 00
Rx: 31 15 1A 19 DB ED CD 5A 91 AF
Send to SAM PICC_SN + ek(RndB).
Tx: 80 41 01 03 0F 80 1B 65 49 41 65 04 31 15 1A 19 DB ED CD 5A
Rx: 61 20
Get from SAM encrypted(RndA + RndB_rotated) + 1st half Session Key
Tx: 00 C0 00 00 20
Rx: F3 10 55 B1 D3 18 91 5B 92 48 16 1F E1 58 D5 CB E9 F3 51 04 41 8A 4E A5 A2 B5 67 CA FF D8 D2 35 90 00
Send PICC encrypted(RndA + RndB_rotated).
Tx: 90 AF 00 00 10 F3 10 55 B1 D3 18 91 5B 92 48 16 1F E1 58 D5 CB 00
Rx: 91 AE
So, this is a guide I have received from my suplier, and i don't have explanations about the apdus used; some i have found them on the internet, some others i guessed.
What I need to know is what does the next command i use:
to SAM module: 80 41 01 03 Lc Data
I need to know what encryption it deploys, why it needs PICC's UID (is this the IV), how can i know RndB, and what is expecting the PICC to end the authentication.
Thanks
Pd: Sorry for the text's format, it seems I'm unable to use correctly the tools for posting, everything gets in the same line it's disgusting...
I solved the problem and finished authentication.
The error was that i was requesting RndB encrypted with keyNo = 0, while corresponding key from SAM's key encryption should be keyNo = 2.
So:
--> 90 0A 00 00 01 02 00
<-- 91 B6 08 CE 9F B5 34 3B 91 AF
Carrying on, i finnish authentication:
--> 90 AF 00 00 10 0F DC FA B6 37 5F 30 34 D7 93 2D A1 3D D6 11 10 00
<-- E9 C2 F2 69 FE 38 78 28 91 00
But now I have the next problem. I've authenticated and I can read PICC's data but i'm afraid it's encrypted. I suppose it is encrypted with session key, so I need some apdu command to be sent to SAM, with data and session key, in order to decrypt data retrieved from PICC.
Am I right? if that is... which would be that SAM APDU?

CertCreateCertificateContext returns CRYPT_E_ASN1_BADTAG / 8009310b

I realize this is a very similar post to others (e.g. this one), but there are details missing from the posts which might be significant for my case.
To start with, here's my simplified program:
#include "stdafx.h"
#include <windows.h>
#include <wincrypt.h>
int _tmain(int argc, _TCHAR* argv[])
{
// usage: CertExtract certpath
char keyFile[] = "C:\\Certificates\\public.crt";
BYTE lp[65536];
SECURITY_ATTRIBUTES sa;
HANDLE hKeyFile;
DWORD bytes;
PCCERT_CONTEXT certContext;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = FALSE;
hKeyFile = CreateFile(keyFile, GENERIC_READ, FILE_SHARE_READ, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hKeyFile) {
if (ReadFile(hKeyFile, lp, GetFileSize(hKeyFile, NULL), &bytes, NULL) && bytes > 0) {
certContext = CertCreateCertificateContext(X509_ASN_ENCODING, lp, bytes);
if (certContext) {
printf("yay!");
CertFreeCertificateContext(certContext);
}
else {
printf("Could not convert certificate to internal form\n");
}
}
else {
printf("Failed to read key file: %s\n", keyFile);
}
}
else {
printf("Failed to open key file: %s\n", keyFile);
}
CloseHandle(hKeyFile);
return 0;
}
In order to create the certificate, I used the following steps with OpenSSL:
C:\Certificates>openssl genrsa -out private.key 1024
Loading 'screen' into random state - done
Generating RSA private key, 1024 bit long modulus
......................................++++++
................++++++
e is 65537 (0x10001)
C:\Certificates>openssl req -new -key private.key -out public.csr
Loading 'screen' into random state - done
C:\Certificates>copy private.key private.key.org
1 file(s) copied.
C:\Certificates>openssl rsa -in private.key.org -out private.key
writing RSA key
C:\Certificates>openssl x509 -req -days 365 -in public.csr -signkey private.key -ou
t public.crt
Loading 'screen' into random state - done
Signature ok
subject=/CN=My Signing Cert
Getting Private key
with the following conf file:
RANDFILE = .rnd
[ req ]
distinguished_name = req_distinguished_name
prompt = no
[ req_distinguished_name ]
commonName = My Signing Cert
The certificate file looks like:
-----BEGIN CERTIFICATE-----
MIIBqzCCARQCCQDUJyWk0OxlRTANBgkqhkiG9w0BAQUFADAaMRgwFgYDVQQDDA9N
eSBTaWduaW5nIENlcnQwHhcNMTYwMTA1MjIzODU5WhcNMTcwMTA0MjIzODU5WjAa
MRgwFgYDVQQDDA9NeSBTaWduaW5nIENlcnQwgZ8wDQYJKoZIhvcNAQEBBQADgY0A
MIGJAoGBAJobIhfSSMLEPeG9SOBelWHo4hjKXe8dT6cllPr6QXdXe2VNLh9fxVlx
spVGFQwjlF3OHYnmSQnY3m2b5wlFNYVuHvy8rUsZWOF4drSbiqWKh0TuJ+4MBeGq
EormTJ+kiGqNm5IVRrTu9OV8f0XQTGV1pxHircQxsGhxY5w0QTjjAgMBAAEwDQYJ
KoZIhvcNAQEFBQADgYEAedqjKfMyIFC8nUbJ6t/Y8D+fJFwCcdwojUFizr78FEwA
IZSas1b1bXSkA+QEooW7pYdBAfzNuD3WfZAIZpqFlr4rPNIqHzYa0OIdDPwzQQLa
3zPKqjj6QeTWEi5/ArzO+sTVv4m3Og3GQjMChb8H/GxsWdbComPVP82DTUet+ZU=
-----END CERTIFICATE-----
Converting the PEM-encoding to hex allows me to identify the parts of the certificate:
30 SEQUENCE //Certificate
(82 01 AB)
30 SEQUENCE //tbsCertificate
(82 01 14)
02 INTEGER //serialNumber
(09)
00 D4 27 25 A4 D0 EC 65 45
30 SEQUENCE //signature
(0D)
06 OBJECT IDENTIFIER
(09)
2A 86 48 86 F7 0D 01 01 05
05 NULL
(00)
30 SEQUENCE //issuer
(1A)
31 SET
(18)
30 SEQUENCE
(16)
06 OBJECT IDENTIFIER
(03)
55 04 03
0C UTF8String
(0F)
4D 79 20 53 69 67 6E 69 6E 67 20 43 65 72 74
30 SEQUENCE //validity
(1E)
17 UTCTime
(0D)
31 36 30 31 30 35 32 32 33 38 35 39 5A
17 UTCTime
(0D)
31 37 30 31 30 34 32 32 33 38 35 39 5A
30 SEQUENCE //subjectName
(1A)
31 SET
(18)
30 SEQUENCE
(16)
06 OBJECT IDENTIFIER
(03)
55 04 03
0C UTF8String
(0F)
4D 79 20 53 69 67 6E 69 6E 67 20 43 65 72 74
30 SEQUENCE //subjectPublicKeyInfo
(81 9F)
30 SEQUENCE //algorithmId
(0D)
06 OBJECT IDENTIFIER //algorithm
(09)
2A 86 48 86 F7 0D 01 01 01
05 NULL
(00)
03 BIT STRING //subjectPublicKey
(81 8D)
[00] //padding bits
30 SEQUENCE //RSAPublicKey
(81 89)
02 INTEGER //modulus
(81 81)
00 9A 1B 22 17 D2 48 C2 C4 3D E1 BD 48 E0 5E 95 61 E8 E2 18 CA 5D EF 1D 4F A7 25 94 FA FA 41 77 57 7B 65 4D 2E 1F 5F C5 59 71 B2 95 46 15 0C 23 94 5D CE 1D 89 E6 49 09 D8 DE 6D 9B E7 09 45 35 85 6E 1E FC BC AD 4B 19 58 E1 78 76 B4 9B 8A A5 8A 87 44 EE 27 EE 0C 05 E1 AA 12 8A E6 4C 9F A4 88 6A 8D 9B 92 15 46 B4 EE F4 E5 7C 7F 45 D0 4C 65 75 A7 11 E2 AD C4 31 B0 68 71 63 9C 34 41 38 E3 02 03 01 00 01
30 SEQUENCE //signatureAlgorithm
(0D)
06 OBJECT IDENTIFIER
(09)
2A 86 48 86 F7 0D 01 01 05
05 NULL
(00)
03 BIT STRING //signatureValue
(81 81)
[00] //padding bits
79 DA A3 29 F3 32 20 50 BC 9D 46 C9 EA DF D8 F0 3F 9F 24 5C 02 71 DC 28 8D 41 62 CE BE FC 14 4C 00 21 94 9A B3 56 F5 6D 74 A4 03 E4 04 A2 85 BB A5 87 41 01 FC CD B8 3D D6 7D 90 08 66 9A 85 96 BE 2B 3C D2 2A 1F 36 1A D0 E2 1D 0C FC 33 41 02 DA DF 33 CA AA 38 FA 41 E4 D6 12 2E 7F 02 BC CE FA C4 D5 BF 89 B7 3A 0D C6 42 33 02 85 BF 07 FC 6C 6C 59 D6 C2 A2 63 D5 3F CD 83 4D 47 AD F9 95
which appears to conform to the X.509 specs (as I would expect it to):
Certificate ::= {
tbsCertificate TBSCertificate,
signatureAlgorithm AlgorithmIdentifier,
signatureValue BIT STRING
}
TBSCertificate ::= SEQUENCE {
version [0] Version DEFAULT v1, <-- what does this mean?
serialNumber INTEGER,
signature AlgorithmIdentifier,
issuer Name,
validity Validity,
subjectName Name,
subjectPublicKeyInfo SubjectPublicKeyInfo
...
}
with the lone exception of the version part, which isn't clear to me whether it is optional or not (though it never seems to be added with certificates I create with OpenSSL).
I can open the certificate to import into a certificate store (and can successfully import to a store), so I don't think anything is specifically wrong with the file/encoding.
When I reach the call to CertCreateCertificateContext, my lp buffer looks like:
-----BEGIN CERTIFICATE-----\nMIIBqzCCARQCCQDUJyWk0OxlRTANBgkqhkiG9w0BAQUFADAaMRgwFgYDVQQDDA9N\neSBTaWduaW5nIENlcnQwHhcNMTYwMTA1MjIzODU5WhcNMTcwMTA0MjIzODU5WjAa\nMRgwFgYDVQQDDA9NeSBTaWduaW5nIENlcnQwgZ8wDQ...
and bytes = 639 -- which is the file size.
I've tried adding logic to strip out the certificate comments, but examples of importing a certificate in this manner don't indicate that should be necessary.
I've tried setting the dwCertEncodingType to X509_ASN_ENCODING | PKCS_7_ASN_ENCODING and PKCS_7_ASN_ENCODING out of desperation (though I don't believe I am using PKCS#7 encoding here...a little fuzzy on that).
Does anyone have any suggestions on what I might be doing incorrectly here? I appreciate it.
I figured out my issue. CertCreateCertificateContext is expecting the binary ASN.1 data, not the PEM-encoded certificate I created with openssl. I figured this out by using a Microsoft certificate generation tool and testing that certificate out:
C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin>makecert.exe -n "CN=Test Signing Cert" -b 0
1/06/2016 -e 01/06/2017 -len 1024 -r C:\Certificates\public_v2.crt
Succeeded
looking at the file in a hex editor, it looked precisely like the ASN.1 binary data. next, I used the Copy to File feature from the certificate viewer that launches when you double-click a certificate to copy my original public.crt file to a DER encoded binary X.509 (.CER) file and verified that my program began to work (that is, the CertCreateCertificateContext was now happy).
so, in case someone else is bumping up against the same issue I was having, here is a complete solution to importing a PEM-encoded certificate from a file into memory for use with the Crypto API:
#include "stdafx.h"
#include <windows.h>
#include <wincrypt.h>
#define LF 0x0A
int _tmain(int argc, _TCHAR* argv[])
{
char keyFile[] = "C:\\Certificates\\public.crt";
BYTE lp[65536];
SECURITY_ATTRIBUTES sa;
HANDLE hKeyFile;
DWORD bytes;
PCCERT_CONTEXT certContext;
BYTE *p;
DWORD flags;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = FALSE;
hKeyFile = CreateFile(keyFile, GENERIC_READ, FILE_SHARE_READ, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hKeyFile) {
if (ReadFile(hKeyFile, lp, GetFileSize(hKeyFile, NULL), &bytes, NULL) && bytes > 0) {
p = lp + bytes;
if (CryptStringToBinary((char *)lp, p - lp, CRYPT_STRING_BASE64_ANY, p, &bytes, NULL, &flags) && bytes > 0) {
certContext = CertCreateCertificateContext(X509_ASN_ENCODING, p, bytes);
if (certContext) {
printf("yay!");
CertFreeCertificateContext(certContext);
}
else {
printf("Could not convert certificate to internal form\n");
}
}
else {
printf("Failed to convert from PEM");
}
}
else {
printf("Failed to read key file: %s\n", keyFile);
}
}
else {
printf("Failed to open key file: %s\n", keyFile);
}
CloseHandle(hKeyFile);
return 0;
}
Note:
because I'm lazy, I decode the PEM encoding to binary in the same BYTE array I used to load the file into -- for this simple test, it was expedient, but if you're looking to implement this sort of thing for real, I wouldn't recommend it

Bash echo command with binary data?

Would someone please explain why this script sometime return only 15 bytes in hex string representation?
for i in {1..10}; do
API_IV=`openssl rand 16`; API_IV_HEX=`echo -n "$API_IV" | od -vt x1 -w16 | awk '{$1="";print}'`; echo $API_IV_HEX;
done
like this:
c2 2a 09 0f 9a cd 64 02 28 06 43 f8 13 80 a5 04
fa c4 ac b1 95 23 7c 36 95 2d 5e 0e bf 05 fe f4
38 55 d3 b4 32 bb 61 f4 fd 17 92 67 e2 9b b4 04
6d a7 f8 46 e9 99 bd 89 87 f9 7f 2b 15 5a 17 8a
11 c8 89 f4 8f 66 93 f1 6d b9 2b 64 7e 01 61 68
93 e3 9d 28 95 e1 c8 92 e5 62 d9 bf 20 b3 1c dd
37 64 ef b0 2f da c7 60 1c c8 20 b8 28 9d f9
29 f0 5a e9 cc 36 66 de 02 82 fc 8e 36 bf 5d d1
b2 57 d8 79 21 df 73 1c af 07 e9 80 0a 67 c6 15
ba 77 cb 92 39 42 39 f9 a4 57 c8 c4 be 62 19 54
If pipe the "openssl rand 16" directly to the od command then it works fine, but I need the binary value. Thanks for your help.
echo, like various other standard commands, considers \x00 as an end-of-string marker. So stop displaying after it.
Maybe you are looking to the -hex option of openssl rand:
sh$ openssl rand 16 -hex
4248bf230fc9dd927ab53f799e2a9708
Given that option is available on your system, your example could be rewritten:
sh$ openssl version
OpenSSL 1.0.1e 11 Feb 2013
sh$ for i in {1..10}; do
openssl rand 16 -hex | sed -e 's|..|& |g' -e 's| $||'
done
20 cb 6b 7a 85 2d 0b fe 9e c7 d0 4b 91 88 1b bb
5d 74 99 5e 05 c9 7d 9d 37 dd 02 f3 23 bb c5 b7
51 e9 0f dc 58 04 5e 30 e3 6b 9f 63 aa fc 95 05
fc 6b b8 cb 05 82 53 85 78 0e 59 13 3b e7 c1 4b
cf fa fc d9 1a 25 df e0 f8 59 71 a6 2c 64 c5 87
93 1a 29 b4 5a 52 77 bb 3f bb 1d 0a 46 5d c8 b4
0c bb c2 b2 b4 89 d4 37 1c 86 0a 7a 58 b8 64 e2
ee fc a7 ec 6c f8 7f 51 04 43 d6 00 d8 79 65 43
b9 73 9e cc 4b 42 9e 64 9d 5b 21 6a 20 b7 c3 16
06 8a 15 22 6a d5 ae ab 9a d2 9f 60 f1 a9 26 bd
If you need to later convert from hex to bytes use this perl one-liner:
echo MY_HEX_STRING |
perl -ne 's/([0-9a-f]{2})/print chr hex $1/gie' |
my_tool_reading_binary_input_from_stdin
(from https://stackoverflow.com/a/1604770/2363712)
Please note I pipe to the client program and o not use a shell variable here, as I think it cannot properly handle the \x00.
As the bash cannot properly deal with binary strings containing \x00 your best bet if you absolutely want to stick with shell programming is to use an intermediate file to store binary data. And not a variable:
This is the idea. Feel free to adapt to your needs:
for i in {1..10}; do
openssl rand 16 > api_iv_$i # better use `mktemp` here
API_IV_HEX=`od -vt x1 -w16 < api_iv_$i | awk '{$1="";print}'`
echo $API_IV_HEX;
done
sh$ bash t.sh
cf 06 ab ab 86 fd ef 22 1a 2c bd 7f 8c 45 27 e5
2a 01 9c 7a fa 15 d3 ea 40 89 8b 26 d5 4f 97 08
55 2e c9 d3 cd 0d 3a 6f 1b a0 fe 38 6d 0e 20 07
fe 60 35 62 17 80 f2 db 64 7a af da 81 ff f7 e0
74 9a 5c 39 0e 1a 6b 89 a3 21 65 01 a3 de c4 1c
c3 11 45 e3 e0 dc 66 a3 e8 fb 5b 8a bd d0 7d 43
a4 ee 80 f8 c8 8b 4e 50 5c dd 21 00 3b d0 bc cf
e2 d5 11 d4 7d 98 08 a7 16 7b 8c 56 44 ba 6d 53
ad 63 65 fd bf 3f 1f 4a a1 c5 d0 58 23 ae d1 47
80 74 f1 d0 b9 00 e5 1d 50 74 53 96 4b ce 59 50
sh$ hexdump -C ./api_iv_10
00000000 80 74 f1 d0 b9 00 e5 1d 50 74 53 96 4b ce 59 50 |.t......PtS.K.YP|
00000010
As a personal opinion, if you really have a lot of binary data processing, I would recommend to switch to some other language more data oriented (Python, ...)
Because the missing byte was an ASCII NUL '\0' '\x00'. The echo command stops printing its argument(s) when it comes across a null byte in each argument.

Resources