msd 5 Posted September 25, 2023 Hello, I have small problem with converting smartcard response to x509 certificate. It look like 3 step process. 1. Smartcard return HEX response 30 82 05 D2 30 82 04 BA A0 03 02 01 02 02 0E 62 20 97 1F 98 E6 F2 89 00 00 00 00 14 AF 30 0D 06 09 2A 86 48 86 F7 0D 01 01 0D 05 00 30 49 31 0B 30 09 06 03 55 04 06 13 02 52 53 31 17 30 15 06 03 55 04 0A 13 0E 50 6F 72 65 73 6B 61 20 55 70 72 61 76 61 31 21 30 1F 06 03 55 04 03 13 18 53 61 6E 64 62 6F 78 20 53 55 46 20 49 73 73 75 69 6E 67 20 43 41 20 31 30 1E 17 0D 32 32 30 31 32 35 30 38 31 39 35 38 5A 17 0D 32 35 30 31 32 35 30 38 32 39 35 38 5A 30 81 C7 31 0B 30 09 06 03 55 04 06 13 02 52 53 31 1B 30 19 06 03 55 04 08 0C 12 D0 9F D0 BE D0 B6 D0 B0 D1 80 D0 B5 D0 B2 D0 B0 D1 86 31 13 30 11 06 03 55 04 07 0C 0A 50 6F C5 BE 61 72 65 76 61 63 31 17 30 15 06 03 55 04 09 13 0E 4D 61 6A 61 6B 6F 76 73 6B 6F 67 20 31 35 31 1B 30 19 06 03 55 04 0A 13 12 4D 53 44 20 41 67 65 6E 63 69 6A 61 20 7A 61 20 49 54 31 1B 30 19 06 03 55 04 0B 13 12 4D 53 44 20 41 67 65 6E 63 69 6A 61 20 7A 61 20 49 54 31 11 30 0F 06 03 55 04 05 13 08 51 42 56 55 41 53 4D 52 31 20 30 1E 06 03 55 04 03 13 17 51 42 56 55 20 4D 53 44 20 41 67 65 6E 63 69 6A 61 20 7A 61 20 49 54 30 82 01 22 30 0D 06 09 2A 86 48 86 F7 0D 01 01 01 05 00 03 82 01 0F 00 30 82 01 0A 02 82 01 01 00 B3 F7 B3 77 B0 4D FC E8 B1 57 1E DD A1 73 E1 00 2A 39 A1 C6 CE 56 8F 8E 16 9E B6 87 F1 B5 6B F9 7B 28 89 22 AA 2E 07 CB 06 AA CF 24 E0 8C A9 73 49 5E C8 2E 75 54 44 C0 D8 14 F5 AD 10 9C BC EB 10 4E 2A 78 44 3D 00 92 3F 1A F4 6F 2D 27 AB 1F C3 80 D9 66 31 24 9B 1E 0E F6 2E 77 62 D6 6A 61 A0 32 01 90 A6 5A C0 5E 48 5B ED 1E 2A 8C 79 46 01 99 23 32 03 5E 9F A1 0B 93 17 2E 89 52 DA 99 BF BF 5A CB 81 78 D7 5C 48 FE C9 07 96 83 4F 9F 74 32 D7 87 2F C4 BF BA 41 CC 91 AF 73 28 E9 D0 1D 2D A2 C0 91 08 D0 E4 60 5A 4D DB 0C 5C 7F B5 B4 C1 8A CA 19 1D 46 27 68 D1 97 1B 21 5E 9F 5A 5C 6E B4 80 99 EE A6 CB FD 65 4B 1F 1C 91 DE 38 AA DB F8 B0 E5 C2 C0 E8 C5 16 37 B5 18 EF 80 0A 3A F7 AA 2D F2 C2 64 25 7C CC F9 1E 31 C8 67 A4 38 6D DE BE 7B D2 09 49 BE 09 5B 2B 24 0A 26 71 02 03 01 00 01 A3 82 02 37 30 82 02 33 30 0F 06 03 55 1D 13 01 01 FF 04 05 30 03 02 01 00 30 0E 06 03 55 1D 0F 01 01 FF 04 04 03 02 04 90 30 17 06 03 55 1D 25 04 10 30 0E 06 0C 2B 06 01 04 01 83 86 20 05 08 03 03 30 81 C5 06 03 55 1D 20 04 81 BD 30 81 BA 30 81 B7 06 0C 2B 06 01 04 01 83 86 20 05 08 04 02 30 81 A6 30 32 06 08 2B 06 01 05 05 07 02 01 16 26 68 74 74 70 3A 2F 2F 70 6B 69 2E 73 61 6E 64 62 6F 78 2E 73 75 66 2E 70 75 72 73 2E 67 6F 76 2E 72 73 2F 70 6B 69 30 70 06 08 2B 06 01 05 05 07 02 02 30 64 1E 62 00 73 00 61 00 6E 00 64 00 62 00 6F 00 78 00 55 00 73 00 65 00 20 00 70 00 4B 00 49 00 53 00 72 00 62 00 69 00 6A 00 61 00 53 00 61 00 6E 00 64 00 62 00 6F 00 78 00 20 00 69 00 73 00 73 00 75 00 61 00 6E 00 63 00 65 00 50 00 6F 00 6C 00 69 00 63 00 79 00 20 00 63 00 6C 00 61 00 73 00 73 00 32 30 32 06 0B 2B 06 01 04 01 83 86 20 05 08 05 04 23 68 74 74 70 73 3A 2F 2F 61 70 69 2E 73 61 6E 64 62 6F 78 2E 73 75 66 2E 70 75 72 73 2E 67 6F 76 2E 72 73 30 18 06 0B 2B 06 01 04 01 83 86 20 05 08 06 04 09 31 30 34 37 37 35 37 33 37 30 1D 06 03 55 1D 0E 04 16 04 14 3C 93 36 92 AE 4C E5 65 BD C9 CE 8B F9 B0 BD A1 17 CE 9E F6 30 1F 06 03 55 1D 23 04 18 30 16 80 14 33 24 82 AB BB 7B F1 55 69 81 18 B8 DE 97 1B 0B DF E4 A1 E1 30 4A 06 03 55 1D 1F 04 43 30 41 30 3F A0 3D A0 3B 86 39 68 74 74 70 3A 2F 2F 70 6B 69 2E 73 61 6E 64 62 6F 78 2E 73 75 66 2E 70 75 72 73 2E 67 6F 76 2E 72 73 2F 70 6B 69 2F 53 55 46 49 43 41 31 53 61 6E 64 62 6F 78 2E 63 72 6C 30 55 06 08 2B 06 01 05 05 07 01 01 04 49 30 47 30 45 06 08 2B 06 01 05 05 07 30 02 86 39 68 74 74 70 3A 2F 2F 70 6B 69 2E 73 61 6E 64 62 6F 78 2E 73 75 66 2E 70 75 72 73 2E 67 6F 76 2E 72 73 2F 70 6B 69 2F 53 55 46 49 43 41 31 53 61 6E 64 62 6F 78 2E 63 65 72 30 0D 06 09 2A 86 48 86 F7 0D 01 01 0D 05 00 03 82 01 01 00 9A 4F CE 46 7B E8 8F 14 D4 E3 D8 6A 83 7D EC 6E 21 3E F7 8D 7A E8 3C D9 F5 68 9F 73 88 AD B8 7E 0D 5E 4A 34 15 68 11 0E A8 74 A6 EA F6 C0 9C C4 0C 2D 9B A6 7D CD 10 8E FE AC 5A 28 54 CF 59 C4 B9 8A D0 EB B6 58 09 52 10 0E D1 27 56 3B 5D 22 0B 1E 88 AF C3 8F 8E 38 11 96 EE 57 79 98 86 82 9E BF 09 E7 E7 D4 F0 13 E4 6D 37 EB 51 F8 92 BD 05 BA A8 CA 53 B7 3B F4 DB D1 9F 71 A4 9F BC 9D 53 DF 84 85 EE CA AA C5 E7 9C C3 F9 48 3F 90 75 B1 BA 22 49 75 4D 1D 6E D0 D5 5C DB 66 D4 9E 7B 14 C5 28 A8 20 83 B7 64 E1 7B A1 EF 5F 9E 93 8F D4 88 F7 38 D8 38 90 9A FA 40 55 9D 61 6F 14 5C 75 B7 4D F8 34 CB FF 01 2E 42 1B B5 B3 9A 94 CA 92 7B 6E 6A 49 C7 EC B6 AF 1B 2F 19 BB 5D 6F 99 67 8E A3 C4 86 B5 A4 8E A9 44 25 29 CD 08 E0 83 0E A9 F0 22 62 EF 1F 78 76 57 31 80 C6 F7 26 BC 2. This HEX response I need to convert to Byte Array 3. I need to convert Byte Array to text representation (string, widestring, ...) I need some function (if Delphi has it or custom) for HEX to ByteArray and then ByteArray to TEXT ? Thanks for the help in advance... Share this post Link to post
Kas Ob. 121 Posted September 25, 2023 3 hours ago, msd said: I need some function (if Delphi has it or custom) for HEX to ByteArray and then ByteArray to TEXT ? Well, may be not exactly what you need, but use it as you see fit. function LoadHexSpaceSeparatedFileIntoTBytes(aFileName: string): string; var i, c: Integer; st: string; LStingList: TStringList; begin LStingList := TStringList.Create; try LStingList.LineBreak := ' '; LStingList.LoadFromFile(aFileName); SetLength(Result, LStingList.Count); c := 1; for i := 0 to LStingList.Count - 1 do begin st := Trim(LStingList.Strings[i]); if (st <> '') and (Length(st) = 2) then begin HexToBin(PChar(@st[1]), PChar(@Result[c]), 1); Inc(c); end; end; SetLength(Result, c); finally LStingList.Free; end; end; Quick use of StringList to separate the values, of course you can parse it on your own and even skip the usage of HexToBin altogether by using your own. 1 Share this post Link to post
FPiette 383 Posted September 25, 2023 3 hours ago, msd said: Smartcard return HEX response I which type of variable to you get that data? 1 Share this post Link to post
msd 5 Posted September 25, 2023 Hello, Kas Ob, Your sample works fine, but I need to convert the HEX response to bytes and then to text representation (so this function doesn't work in the second step). I get responses in Delphi as TBytes. Share this post Link to post
Angus Robertson 574 Posted September 25, 2023 Look-up base64 conversion in the help, then break the lines to 64 long and add the --- header and footer you see in a PEM certificate file. Angus 1 Share this post Link to post
FPiette 383 Posted September 25, 2023 1 hour ago, msd said: I get responses in Delphi as TBytes TBytes is a kind of byte array. You say that the smartcard returns "30 82 05 ....". Do you mean the TBytes[0] containe ascii '3', TBytes[1] contains ascii '0', TBytes[2] contains ascii space and so on? OR Do you mean TBytes[0] contain $30, TBytes[1] containes $82 and so on. It would help if you correctly explain what you really get and what you printed out to show in your message. I would also help if you tell us the exact x509 certificate you need: .pem, .cer, .crt, .der or other file. I guess the smartcard return a .der (binary). Did you already read this resource : https://www.ssl.com/guide/pem-der-crt-and-cer-x-509-encodings-and-conversions/ 1 Share this post Link to post
Kas Ob. 121 Posted September 26, 2023 13 hours ago, msd said: Your sample works fine, but I need to convert the HEX response to bytes and then to text representation (so this function doesn't work in the second step). I get responses in Delphi as TBytes. Well, where to start ?!! See the first two hex values 3082 , from the first look i know this is an ASN.1 structure represent a what is most likely a X.509 certificate in raw content, so no texts or strings out of the box. Your question is not understandable, so i will guess here and assume that you want to get the text strings inside the certificate fields and extensions , right ? so here adjusted code function LoadHexSpaceSeparatedFileIntoAnsiString(aFileName: string): AnsiString; var i, c: Integer; st: string; LStingList: TStringList; begin LStingList := TStringList.Create; try LStingList.LineBreak := ' '; LStingList.LoadFromFile(aFileName); SetLength(Result, LStingList.Count); c := 1; for i := 0 to LStingList.Count - 1 do begin st := Trim(LStingList.Strings[i]); if (st <> '') and (Length(st) = 2) then begin HexToBin(PChar(@st[1]), PAnsiChar(@Result[c]), 1); Inc(c); end; end; SetLength(Result, c); finally LStingList.Free; end; end; procedure TForm10.Button1Click(Sender: TObject); var Cer:string; Stream:TMemoryStream; begin Cer := LoadHexSpaceSeparatedFileIntoAnsiString('HexFile.txt'); //Memo1.Lines.Add(Cer); Stream := TMemoryStream.Create; try Stream.Write(Ansistring(Cer)[1],Length(Cer)); Stream.Position := 0; Stream.SaveToFile('HexFile.der'); finally Stream.Free; end; end; This will give you fully restored certificate in BER format (also DER in this case) also if you grabbed that hex in full and pasted it in this site https://lapo.it/asn1js/ after decode you will have fully decoded ASN.1 structure, so when you ask for strings, i will assume you want the "issued to" field content, in that case then use the ICS examples and demoes to parse the X509 certificate and get you !! strings !! Away from that, please reform the question, so we can help. Also FPiette had asked, i don't get how did you get that hex in first place ??!!, my answer above is , WHAAT, ok, not my problem he asks for strings so lets make it a string, but it will not be a string, it is a complex structure with few readable string fields. Hope that clear things and helps. ps : The key usage (OID 1.3.6.1.4.1.49952.5.8.3.3) of this certificate is not recorded in any online OID databases, meaning this is proprietary and undocumented usage, also being issued by a governmental body, you really should be extra careful when it comes to such certificates and where its private key, such certificates usually locked to a hardware or locked to specific usage with specific software. 1 Share this post Link to post
msd 5 Posted September 29, 2023 Hello FPiette , Yes, it is an array of bytes, and I represented it as a formated string in my first post. Hello, Kas Ob. Your demo is working fine; it is an ASN.1 x509 certificate. I took a long time to study all aspects of this post, and I found that my smart card always returns TBytes as a response, like it was represented in my first post. So I have one more question about this subject (I'll give you a sample). When I call some kind of SUM from Smart Card over the APDU command, I get an answer like this: 00 00 08 99 7D FB 1A 03 8D 7E A4 C6 80 00 (this is a response in HEX format as TBytes in Delphi). In this answer, I have the first 7 bytes as the control sum and the second 7 bytes as the total sum (I know that the second number is 1.000.000.000). My question is how to convert the array of bytes (TBytes data type) to a string or number in this case. P.S. I can give you a piece of code in Java that is working for this sample: ByteBuffer bb = ByteBuffer.allocate(16); bb.put((byte)0); bb.put(answer.getData(), 0, 7); bb.put((byte)0); bb.put(answer.getData(), 7, 7); bb.position(0); long controlSum = bb.getLong(); long totalSum = bb.getLong(); Thanks for all the help and assistance in advance. Share this post Link to post
FPiette 383 Posted September 30, 2023 (edited) The way numbers are represented is platform dependent. I don't know any platform which use 56 bit for an integer (7 bytes you said). Usually you have 8, 16, 32 ou 64 bits integers (Byte, Short, Integer and Int64 in Delphi). Java code you present make me think that the 7 bytes in the TBytes has to be prefixed by a 8th byte to form a 8 byte (64 bit) integer. (decimal) 1.000.000.000 is (hex)3B 9A CA 00. I don't see thoses bytes in the TBytes you show. So the representation is not direct, whatever the byte order is. Maybe the number is encrypted or it is not 1.000.000.000 ? Edited September 30, 2023 by FPiette 1 1 Share this post Link to post
msd 5 Posted September 30, 2023 The original info from the official documentation is that I got, for example, this 00 00 08 99 7D FB 1A 03 8D 7E A4 C6 80 00 response. I need to convert this data from hex to bytes and use half for the control sum and another half for the total sum. As I can see in their example, they created 2 separate arrays of bytes, set the first byte to 00, and then added the rest of the 7 from the response. I try to convert this method in Delphi's way like this: SetLength(answer, 14); answer[00] := $00; answer[01] := $00; answer[02] := $08; answer[03] := $99; answer[04] := $06; answer[05] := $F6; answer[06] := $5A; answer[07] := $03; answer[08] := $8D; answer[09] := $7E; answer[10] := $A4; answer[11] := $C6; answer[12] := $80; answer[13] := $00; SetLength(bb, 16); bb[0] := 0; Move(answer[0], bb[1], 7); bb[8] := 0; Move(answer[7], bb[9], 7); Move(bb[0], controlSum, SizeOf(Int64)); Move(bb[8], totalSum, SizeOf(Int64)); in this example controlSum is 3.693.490,87 and totalSum is 100.000.000.000,00. this is values behind this response in hex format. Thanks one again for all... 1 Share this post Link to post
Kas Ob. 121 Posted September 30, 2023 I have no knowledge with smart card ! FPiette answer is right on point. You miss read/write the number (or your source of information wasn't clear) as it is 1000.000.000.000.000 , in hex is 38D7EA4C68000, it is little endian meaning the first byte is zero will not change the value. was going to ask if you can do it on your own then .... but why not program SmallerHex; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, System.Classes; function HexStringToBytes(const HexString: string): TBytes; var i, c: Integer; st: string; LStingList: TStringList; begin LStingList := TStringList.Create; try LStingList.LineBreak := ' '; LStingList.Text := HexString; SetLength(Result, LStingList.Count); c := 0; for i := 0 to LStingList.Count - 1 do begin st := Trim(LStingList.Strings[i]); if (st <> '') and (Length(st) = 2) then begin HexToBin(PChar(@st[1]), PAnsiChar(@Result[c]), 1); Inc(c); end; end; SetLength(Result, c); finally LStingList.Free; end; end; function BinaryToUInt64_BE(Buffer: PByte; Len: Integer): UInt64; begin if Len > SizeOf(Result) then raise Exception.Create('Requested Size for UInt64 can''t be longer than ' + IntToStr(SizeOf (Result))); Result := 0; while Len > 0 do begin Result := Result shl 8; Result := Result or Buffer^; Inc(Buffer); Dec(Len); end; end; procedure DecodeSumOrSomethingInto2UInt64; var HexBytes: TBytes; First, Second: UInt64; begin HexBytes := HexStringToBytes('00 00 08 99 7D FB 1A 03 8D 7E A4 C6 80 00'); First := BinaryToUInt64_BE(@HexBytes[0], 7); Second := BinaryToUInt64_BE(@HexBytes[7], 7); Writeln(First); Writeln(Second); end; begin DecodeSumOrSomethingInto2UInt64; Readln; end. The result 36934908698 1000000000000000 1 Share this post Link to post
Kas Ob. 121 Posted September 30, 2023 5 minutes ago, msd said: in this example controlSum is 3.693.490,87 and totalSum is 100.000.000.000,00. this is values behind this response in hex format. I see you figured it out , congratulation ! 1 Share this post Link to post
msd 5 Posted September 30, 2023 Hello, Kas Ob, Your function works perfectly, and thanks for this sample method. I want to ask one more question: which library or how to completely parse the X509 cert from Delphi to get all the details and data + public key? Thanks in advance... Share this post Link to post
FPiette 383 Posted September 30, 2023 31 minutes ago, msd said: which library or how to completely parse the X509 cert from Delphi to get all the details and data + public key? ICS (Internet Component Suite) has two units which handle X509 certificates. OverbyteIcsSslX509Certs.pas and OverbyteIcsSslX509Utils.pas. They are somewhat an encapsulation of OpenSSL library and Windows Library. Although I'm ICS main author, I'm not the right person to explain the details. Maybe you should read this post in the support mailing list and start a new post if you have more questions. BTW: ICS is freeware. Look at https://wiki.overbyte.eu. 1 Share this post Link to post
msd 5 Posted September 30, 2023 56 minutes ago, FPiette said: ICS (Internet Component Suite) has two units which handle X509 certificates. OverbyteIcsSslX509Certs.pas and OverbyteIcsSslX509Utils.pas. They are somewhat an encapsulation of OpenSSL library and Windows Library. Although I'm ICS main author, I'm not the right person to explain the details. Maybe you should read this post in the support mailing list and start a new post if you have more questions. BTW: ICS is freeware. Look at https://wiki.overbyte.eu. Very, very, very good and useful toolset with great documentation and a lot of features 🙂 Next weekend we are doing serious testing for ICS and middleware (we have a lot of net-based projects and we need to add a unique solution for online and network operations and one big KBMMW-based project that needs to be refreshed because of performance, security, and stability of data). Thanks again for all the information... Share this post Link to post