/src/opensc/src/libopensc/simpletlv.c
Line | Count | Source |
1 | | /* |
2 | | * simpletlv.c: Simple TLV encoding and decoding functions |
3 | | * |
4 | | * Copyright (C) 2016 Red Hat, Inc. |
5 | | * |
6 | | * Authors: Robert Relyea <rrelyea@redhat.com> |
7 | | * Jakub Jelen <jjelen@redhat.com> |
8 | | * |
9 | | * This library is free software; you can redistribute it and/or |
10 | | * modify it under the terms of the GNU Lesser General Public |
11 | | * License as published by the Free Software Foundation; either |
12 | | * version 2.1 of the License, or (at your option) any later version. |
13 | | * |
14 | | * This library is distributed in the hope that it will be useful, |
15 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 | | * Lesser General Public License for more details. |
18 | | * |
19 | | * You should have received a copy of the GNU Lesser General Public |
20 | | * License along with this library; if not, write to the Free Software |
21 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
22 | | */ |
23 | | |
24 | | #ifdef HAVE_CONFIG_H |
25 | | #include "config.h" |
26 | | #endif |
27 | | |
28 | | #include <stdio.h> |
29 | | #include <string.h> |
30 | | #include <ctype.h> |
31 | | #include <assert.h> |
32 | | #include <stdlib.h> |
33 | | |
34 | | #include "internal.h" |
35 | | #include "simpletlv.h" |
36 | | |
37 | | /* |
38 | | * Put a tag/length record to a file in Simple TLV based on the datalen |
39 | | * content length. |
40 | | */ |
41 | | int |
42 | | sc_simpletlv_put_tag(u8 tag, size_t datalen, u8 *out, size_t outlen, u8 **ptr) |
43 | 17.4k | { |
44 | 17.4k | u8 *p = out; |
45 | | |
46 | 17.4k | if (outlen < 2 || (outlen < 4 && datalen >= 0xff)) |
47 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
48 | | |
49 | | /* tag is just number between 0x01 and 0xFE */ |
50 | 17.4k | if (tag == 0x00 || tag == 0xff) |
51 | 6.37k | return SC_ERROR_INVALID_ARGUMENTS; |
52 | 11.0k | if (datalen > 0xffff) { |
53 | | /* we can't store more than two bytes in Simple TLV */ |
54 | 0 | return SC_ERROR_WRONG_LENGTH; |
55 | 0 | } |
56 | | |
57 | 11.0k | *p++ = tag; /* tag is single byte */ |
58 | 11.0k | if (datalen < 0xff) { |
59 | | /* short value up to 255 */ |
60 | 10.7k | *p++ = (u8)datalen; /* is in the second byte */ |
61 | 10.7k | } else { |
62 | | /* longer values up to 65535 */ |
63 | 355 | *p++ = (u8)0xff; /* first byte is 0xff */ |
64 | 355 | *p++ = (u8)datalen & 0xff; |
65 | 355 | *p++ = (u8)(datalen >> 8) & 0xff; /* LE */ |
66 | 355 | } |
67 | 11.0k | if (ptr != NULL) |
68 | 11.0k | *ptr = p; |
69 | 11.0k | return SC_SUCCESS; |
70 | 11.0k | } |
71 | | |
72 | | /* Read the TL file and return appropriate tag and the length of associated |
73 | | * content. |
74 | | */ |
75 | | int |
76 | | sc_simpletlv_read_tag(const u8 **buf, size_t buflen, u8 *tag_out, size_t *taglen) |
77 | 499k | { |
78 | 499k | u8 tag; |
79 | 499k | size_t left = buflen, len; |
80 | 499k | const u8 *p = *buf; |
81 | | |
82 | 499k | *buf = NULL; |
83 | | |
84 | 499k | if (left < 2) { |
85 | 4.46k | return SC_ERROR_INVALID_TLV_OBJECT; |
86 | 4.46k | } |
87 | 495k | tag = *p; |
88 | 495k | p++; |
89 | 495k | len = *p; |
90 | 495k | p++; |
91 | 495k | left -= 2; |
92 | | |
93 | 495k | if (len == 0xff) { |
94 | | /* don't crash on bad data */ |
95 | 8.87k | if (left < 2) { |
96 | 1.57k | return SC_ERROR_INVALID_TLV_OBJECT; |
97 | 1.57k | } |
98 | | /* skip two bytes (the size) */ |
99 | 7.30k | len = lebytes2ushort(p); |
100 | 7.30k | p += 2; |
101 | 7.30k | left -= 2; |
102 | 7.30k | } |
103 | | |
104 | 493k | *tag_out = tag; |
105 | 493k | *taglen = len; |
106 | 493k | *buf = p; |
107 | | |
108 | 493k | if (len > left) |
109 | 34.5k | return SC_ERROR_TLV_END_OF_CONTENTS; |
110 | | |
111 | 459k | return SC_SUCCESS; |
112 | 493k | } |