0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/asn1_encoder.h>
0009 #include <linux/bug.h>
0010 #include <linux/string.h>
0011 #include <linux/module.h>
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023 unsigned char *
0024 asn1_encode_integer(unsigned char *data, const unsigned char *end_data,
0025 s64 integer)
0026 {
0027 int data_len = end_data - data;
0028 unsigned char *d = &data[2];
0029 bool found = false;
0030 int i;
0031
0032 if (WARN(integer < 0,
0033 "BUG: integer encode only supports positive integers"))
0034 return ERR_PTR(-EINVAL);
0035
0036 if (IS_ERR(data))
0037 return data;
0038
0039
0040 if (data_len < 3)
0041 return ERR_PTR(-EINVAL);
0042
0043
0044 data_len -= 2;
0045
0046 data[0] = _tag(UNIV, PRIM, INT);
0047 if (integer == 0) {
0048 *d++ = 0;
0049 goto out;
0050 }
0051
0052 for (i = sizeof(integer); i > 0 ; i--) {
0053 int byte = integer >> (8 * (i - 1));
0054
0055 if (!found && byte == 0)
0056 continue;
0057
0058
0059
0060
0061
0062
0063
0064 if (!found && (byte & 0x80)) {
0065
0066
0067
0068
0069 *d++ = 0;
0070 data_len--;
0071 }
0072
0073 found = true;
0074 if (data_len == 0)
0075 return ERR_PTR(-EINVAL);
0076
0077 *d++ = byte;
0078 data_len--;
0079 }
0080
0081 out:
0082 data[1] = d - data - 2;
0083
0084 return d;
0085 }
0086 EXPORT_SYMBOL_GPL(asn1_encode_integer);
0087
0088
0089 static int asn1_encode_oid_digit(unsigned char **_data, int *data_len, u32 oid)
0090 {
0091 unsigned char *data = *_data;
0092 int start = 7 + 7 + 7 + 7;
0093 int ret = 0;
0094
0095 if (*data_len < 1)
0096 return -EINVAL;
0097
0098
0099 if (oid == 0) {
0100 *data++ = 0x80;
0101 (*data_len)--;
0102 goto out;
0103 }
0104
0105 while (oid >> start == 0)
0106 start -= 7;
0107
0108 while (start > 0 && *data_len > 0) {
0109 u8 byte;
0110
0111 byte = oid >> start;
0112 oid = oid - (byte << start);
0113 start -= 7;
0114 byte |= 0x80;
0115 *data++ = byte;
0116 (*data_len)--;
0117 }
0118
0119 if (*data_len > 0) {
0120 *data++ = oid;
0121 (*data_len)--;
0122 } else {
0123 ret = -EINVAL;
0124 }
0125
0126 out:
0127 *_data = data;
0128 return ret;
0129 }
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140 unsigned char *
0141 asn1_encode_oid(unsigned char *data, const unsigned char *end_data,
0142 u32 oid[], int oid_len)
0143 {
0144 int data_len = end_data - data;
0145 unsigned char *d = data + 2;
0146 int i, ret;
0147
0148 if (WARN(oid_len < 2, "OID must have at least two elements"))
0149 return ERR_PTR(-EINVAL);
0150
0151 if (WARN(oid_len > 32, "OID is too large"))
0152 return ERR_PTR(-EINVAL);
0153
0154 if (IS_ERR(data))
0155 return data;
0156
0157
0158
0159 if (data_len < 3)
0160 return ERR_PTR(-EINVAL);
0161
0162 data[0] = _tag(UNIV, PRIM, OID);
0163 *d++ = oid[0] * 40 + oid[1];
0164
0165 data_len -= 3;
0166
0167 for (i = 2; i < oid_len; i++) {
0168 ret = asn1_encode_oid_digit(&d, &data_len, oid[i]);
0169 if (ret < 0)
0170 return ERR_PTR(ret);
0171 }
0172
0173 data[1] = d - data - 2;
0174
0175 return d;
0176 }
0177 EXPORT_SYMBOL_GPL(asn1_encode_oid);
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191 static int asn1_encode_length(unsigned char **data, int *data_len, int len)
0192 {
0193 if (*data_len < 1)
0194 return -EINVAL;
0195
0196 if (len < 0) {
0197 *((*data)++) = 0;
0198 (*data_len)--;
0199 return 0;
0200 }
0201
0202 if (len <= 0x7f) {
0203 *((*data)++) = len;
0204 (*data_len)--;
0205 return 0;
0206 }
0207
0208 if (*data_len < 2)
0209 return -EINVAL;
0210
0211 if (len <= 0xff) {
0212 *((*data)++) = 0x81;
0213 *((*data)++) = len & 0xff;
0214 *data_len -= 2;
0215 return 0;
0216 }
0217
0218 if (*data_len < 3)
0219 return -EINVAL;
0220
0221 if (len <= 0xffff) {
0222 *((*data)++) = 0x82;
0223 *((*data)++) = (len >> 8) & 0xff;
0224 *((*data)++) = len & 0xff;
0225 *data_len -= 3;
0226 return 0;
0227 }
0228
0229 if (WARN(len > 0xffffff, "ASN.1 length can't be > 0xffffff"))
0230 return -EINVAL;
0231
0232 if (*data_len < 4)
0233 return -EINVAL;
0234 *((*data)++) = 0x83;
0235 *((*data)++) = (len >> 16) & 0xff;
0236 *((*data)++) = (len >> 8) & 0xff;
0237 *((*data)++) = len & 0xff;
0238 *data_len -= 4;
0239
0240 return 0;
0241 }
0242
0243
0244
0245
0246
0247
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269 unsigned char *
0270 asn1_encode_tag(unsigned char *data, const unsigned char *end_data,
0271 u32 tag, const unsigned char *string, int len)
0272 {
0273 int data_len = end_data - data;
0274 int ret;
0275
0276 if (WARN(tag > 30, "ASN.1 tag can't be > 30"))
0277 return ERR_PTR(-EINVAL);
0278
0279 if (!string && WARN(len > 127,
0280 "BUG: recode tag is too big (>127)"))
0281 return ERR_PTR(-EINVAL);
0282
0283 if (IS_ERR(data))
0284 return data;
0285
0286 if (!string && len > 0) {
0287
0288
0289
0290
0291
0292 data -= 2;
0293 data_len = 2;
0294 }
0295
0296 if (data_len < 2)
0297 return ERR_PTR(-EINVAL);
0298
0299 *(data++) = _tagn(CONT, CONS, tag);
0300 data_len--;
0301 ret = asn1_encode_length(&data, &data_len, len);
0302 if (ret < 0)
0303 return ERR_PTR(ret);
0304
0305 if (!string)
0306 return data;
0307
0308 if (data_len < len)
0309 return ERR_PTR(-EINVAL);
0310
0311 memcpy(data, string, len);
0312 data += len;
0313
0314 return data;
0315 }
0316 EXPORT_SYMBOL_GPL(asn1_encode_tag);
0317
0318
0319
0320
0321
0322
0323
0324
0325
0326
0327 unsigned char *
0328 asn1_encode_octet_string(unsigned char *data,
0329 const unsigned char *end_data,
0330 const unsigned char *string, u32 len)
0331 {
0332 int data_len = end_data - data;
0333 int ret;
0334
0335 if (IS_ERR(data))
0336 return data;
0337
0338
0339 if (data_len < 2)
0340 return ERR_PTR(-EINVAL);
0341
0342 *(data++) = _tag(UNIV, PRIM, OTS);
0343 data_len--;
0344
0345 ret = asn1_encode_length(&data, &data_len, len);
0346 if (ret)
0347 return ERR_PTR(ret);
0348
0349 if (data_len < len)
0350 return ERR_PTR(-EINVAL);
0351
0352 memcpy(data, string, len);
0353 data += len;
0354
0355 return data;
0356 }
0357 EXPORT_SYMBOL_GPL(asn1_encode_octet_string);
0358
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368
0369
0370
0371
0372 unsigned char *
0373 asn1_encode_sequence(unsigned char *data, const unsigned char *end_data,
0374 const unsigned char *seq, int len)
0375 {
0376 int data_len = end_data - data;
0377 int ret;
0378
0379 if (!seq && WARN(len > 127,
0380 "BUG: recode sequence is too big (>127)"))
0381 return ERR_PTR(-EINVAL);
0382
0383 if (IS_ERR(data))
0384 return data;
0385
0386 if (!seq && len >= 0) {
0387
0388
0389
0390
0391
0392 data -= 2;
0393 data_len = 2;
0394 }
0395
0396 if (data_len < 2)
0397 return ERR_PTR(-EINVAL);
0398
0399 *(data++) = _tag(UNIV, CONS, SEQ);
0400 data_len--;
0401
0402 ret = asn1_encode_length(&data, &data_len, len);
0403 if (ret)
0404 return ERR_PTR(ret);
0405
0406 if (!seq)
0407 return data;
0408
0409 if (data_len < len)
0410 return ERR_PTR(-EINVAL);
0411
0412 memcpy(data, seq, len);
0413 data += len;
0414
0415 return data;
0416 }
0417 EXPORT_SYMBOL_GPL(asn1_encode_sequence);
0418
0419
0420
0421
0422
0423
0424
0425 unsigned char *
0426 asn1_encode_boolean(unsigned char *data, const unsigned char *end_data,
0427 bool val)
0428 {
0429 int data_len = end_data - data;
0430
0431 if (IS_ERR(data))
0432 return data;
0433
0434
0435 if (data_len < 3)
0436 return ERR_PTR(-EINVAL);
0437
0438 *(data++) = _tag(UNIV, PRIM, BOOL);
0439 data_len--;
0440
0441 asn1_encode_length(&data, &data_len, 1);
0442
0443 if (val)
0444 *(data++) = 1;
0445 else
0446 *(data++) = 0;
0447
0448 return data;
0449 }
0450 EXPORT_SYMBOL_GPL(asn1_encode_boolean);
0451
0452 MODULE_LICENSE("GPL");