1 // SPDX-License-Identifier: GPL-2.0-only 1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 2 /* 3 * Simple encoder primitives for ASN.1 BER/DER 3 * Simple encoder primitives for ASN.1 BER/DER/CER 4 * 4 * 5 * Copyright (C) 2019 James.Bottomley@HansenPa 5 * Copyright (C) 2019 James.Bottomley@HansenPartnership.com 6 */ 6 */ 7 7 8 #include <linux/asn1_encoder.h> 8 #include <linux/asn1_encoder.h> 9 #include <linux/bug.h> 9 #include <linux/bug.h> 10 #include <linux/string.h> 10 #include <linux/string.h> 11 #include <linux/module.h> 11 #include <linux/module.h> 12 12 13 /** 13 /** 14 * asn1_encode_integer() - encode positive int 14 * asn1_encode_integer() - encode positive integer to ASN.1 15 * @data: pointer to the pointer to the 15 * @data: pointer to the pointer to the data 16 * @end_data: end of data pointer, points on 16 * @end_data: end of data pointer, points one beyond last usable byte in @data 17 * @integer: integer to be encoded 17 * @integer: integer to be encoded 18 * 18 * 19 * This is a simplified encoder: it only curre 19 * This is a simplified encoder: it only currently does 20 * positive integers, but it should be simple 20 * positive integers, but it should be simple enough to add the 21 * negative case if a use comes along. 21 * negative case if a use comes along. 22 */ 22 */ 23 unsigned char * 23 unsigned char * 24 asn1_encode_integer(unsigned char *data, const 24 asn1_encode_integer(unsigned char *data, const unsigned char *end_data, 25 s64 integer) 25 s64 integer) 26 { 26 { 27 int data_len = end_data - data; 27 int data_len = end_data - data; 28 unsigned char *d = &data[2]; 28 unsigned char *d = &data[2]; 29 bool found = false; 29 bool found = false; 30 int i; 30 int i; 31 31 32 if (WARN(integer < 0, 32 if (WARN(integer < 0, 33 "BUG: integer encode only sup 33 "BUG: integer encode only supports positive integers")) 34 return ERR_PTR(-EINVAL); 34 return ERR_PTR(-EINVAL); 35 35 36 if (IS_ERR(data)) 36 if (IS_ERR(data)) 37 return data; 37 return data; 38 38 39 /* need at least 3 bytes for tag, leng 39 /* need at least 3 bytes for tag, length and integer encoding */ 40 if (data_len < 3) 40 if (data_len < 3) 41 return ERR_PTR(-EINVAL); 41 return ERR_PTR(-EINVAL); 42 42 43 /* remaining length where at d (the st 43 /* remaining length where at d (the start of the integer encoding) */ 44 data_len -= 2; 44 data_len -= 2; 45 45 46 data[0] = _tag(UNIV, PRIM, INT); 46 data[0] = _tag(UNIV, PRIM, INT); 47 if (integer == 0) { 47 if (integer == 0) { 48 *d++ = 0; 48 *d++ = 0; 49 goto out; 49 goto out; 50 } 50 } 51 51 52 for (i = sizeof(integer); i > 0 ; i--) 52 for (i = sizeof(integer); i > 0 ; i--) { 53 int byte = integer >> (8 * (i 53 int byte = integer >> (8 * (i - 1)); 54 54 55 if (!found && byte == 0) 55 if (!found && byte == 0) 56 continue; 56 continue; 57 57 58 /* 58 /* 59 * for a positive number the f 59 * for a positive number the first byte must have bit 60 * 7 clear in two's complement 60 * 7 clear in two's complement (otherwise it's a 61 * negative number) so prepend 61 * negative number) so prepend a leading zero if 62 * that's not the case 62 * that's not the case 63 */ 63 */ 64 if (!found && (byte & 0x80)) { 64 if (!found && (byte & 0x80)) { 65 /* 65 /* 66 * no check needed her 66 * no check needed here, we already know we 67 * have len >= 1 67 * have len >= 1 68 */ 68 */ 69 *d++ = 0; 69 *d++ = 0; 70 data_len--; 70 data_len--; 71 } 71 } 72 72 73 found = true; 73 found = true; 74 if (data_len == 0) 74 if (data_len == 0) 75 return ERR_PTR(-EINVAL 75 return ERR_PTR(-EINVAL); 76 76 77 *d++ = byte; 77 *d++ = byte; 78 data_len--; 78 data_len--; 79 } 79 } 80 80 81 out: 81 out: 82 data[1] = d - data - 2; 82 data[1] = d - data - 2; 83 83 84 return d; 84 return d; 85 } 85 } 86 EXPORT_SYMBOL_GPL(asn1_encode_integer); 86 EXPORT_SYMBOL_GPL(asn1_encode_integer); 87 87 88 /* calculate the base 128 digit values setting 88 /* calculate the base 128 digit values setting the top bit of the first octet */ 89 static int asn1_encode_oid_digit(unsigned char 89 static int asn1_encode_oid_digit(unsigned char **_data, int *data_len, u32 oid) 90 { 90 { 91 unsigned char *data = *_data; 91 unsigned char *data = *_data; 92 int start = 7 + 7 + 7 + 7; 92 int start = 7 + 7 + 7 + 7; 93 int ret = 0; 93 int ret = 0; 94 94 95 if (*data_len < 1) 95 if (*data_len < 1) 96 return -EINVAL; 96 return -EINVAL; 97 97 98 /* quick case */ 98 /* quick case */ 99 if (oid == 0) { 99 if (oid == 0) { 100 *data++ = 0x80; 100 *data++ = 0x80; 101 (*data_len)--; 101 (*data_len)--; 102 goto out; 102 goto out; 103 } 103 } 104 104 105 while (oid >> start == 0) 105 while (oid >> start == 0) 106 start -= 7; 106 start -= 7; 107 107 108 while (start > 0 && *data_len > 0) { 108 while (start > 0 && *data_len > 0) { 109 u8 byte; 109 u8 byte; 110 110 111 byte = oid >> start; 111 byte = oid >> start; 112 oid = oid - (byte << start); 112 oid = oid - (byte << start); 113 start -= 7; 113 start -= 7; 114 byte |= 0x80; 114 byte |= 0x80; 115 *data++ = byte; 115 *data++ = byte; 116 (*data_len)--; 116 (*data_len)--; 117 } 117 } 118 118 119 if (*data_len > 0) { 119 if (*data_len > 0) { 120 *data++ = oid; 120 *data++ = oid; 121 (*data_len)--; 121 (*data_len)--; 122 } else { 122 } else { 123 ret = -EINVAL; 123 ret = -EINVAL; 124 } 124 } 125 125 126 out: 126 out: 127 *_data = data; 127 *_data = data; 128 return ret; 128 return ret; 129 } 129 } 130 130 131 /** 131 /** 132 * asn1_encode_oid() - encode an oid to ASN.1 132 * asn1_encode_oid() - encode an oid to ASN.1 133 * @data: position to begin encoding at 133 * @data: position to begin encoding at 134 * @end_data: end of data pointer, points on 134 * @end_data: end of data pointer, points one beyond last usable byte in @data 135 * @oid: array of oids 135 * @oid: array of oids 136 * @oid_len: length of oid array 136 * @oid_len: length of oid array 137 * 137 * 138 * this encodes an OID up to ASN.1 when presen 138 * this encodes an OID up to ASN.1 when presented as an array of OID values 139 */ 139 */ 140 unsigned char * 140 unsigned char * 141 asn1_encode_oid(unsigned char *data, const uns 141 asn1_encode_oid(unsigned char *data, const unsigned char *end_data, 142 u32 oid[], int oid_len) 142 u32 oid[], int oid_len) 143 { 143 { 144 int data_len = end_data - data; 144 int data_len = end_data - data; 145 unsigned char *d = data + 2; 145 unsigned char *d = data + 2; 146 int i, ret; 146 int i, ret; 147 147 148 if (WARN(oid_len < 2, "OID must have a 148 if (WARN(oid_len < 2, "OID must have at least two elements")) 149 return ERR_PTR(-EINVAL); 149 return ERR_PTR(-EINVAL); 150 150 151 if (WARN(oid_len > 32, "OID is too lar 151 if (WARN(oid_len > 32, "OID is too large")) 152 return ERR_PTR(-EINVAL); 152 return ERR_PTR(-EINVAL); 153 153 154 if (IS_ERR(data)) 154 if (IS_ERR(data)) 155 return data; 155 return data; 156 156 157 157 158 /* need at least 3 bytes for tag, leng 158 /* need at least 3 bytes for tag, length and OID encoding */ 159 if (data_len < 3) 159 if (data_len < 3) 160 return ERR_PTR(-EINVAL); 160 return ERR_PTR(-EINVAL); 161 161 162 data[0] = _tag(UNIV, PRIM, OID); 162 data[0] = _tag(UNIV, PRIM, OID); 163 *d++ = oid[0] * 40 + oid[1]; 163 *d++ = oid[0] * 40 + oid[1]; 164 164 165 data_len -= 3; 165 data_len -= 3; 166 166 >> 167 ret = 0; >> 168 167 for (i = 2; i < oid_len; i++) { 169 for (i = 2; i < oid_len; i++) { 168 ret = asn1_encode_oid_digit(&d 170 ret = asn1_encode_oid_digit(&d, &data_len, oid[i]); 169 if (ret < 0) 171 if (ret < 0) 170 return ERR_PTR(ret); 172 return ERR_PTR(ret); 171 } 173 } 172 174 173 data[1] = d - data - 2; 175 data[1] = d - data - 2; 174 176 175 return d; 177 return d; 176 } 178 } 177 EXPORT_SYMBOL_GPL(asn1_encode_oid); 179 EXPORT_SYMBOL_GPL(asn1_encode_oid); 178 180 179 /** 181 /** 180 * asn1_encode_length() - encode a length to f 182 * asn1_encode_length() - encode a length to follow an ASN.1 tag 181 * @data: pointer to encode at 183 * @data: pointer to encode at 182 * @data_len: pointer to remaining length (adj 184 * @data_len: pointer to remaining length (adjusted by routine) 183 * @len: length to encode 185 * @len: length to encode 184 * 186 * 185 * This routine can encode lengths up to 65535 187 * This routine can encode lengths up to 65535 using the ASN.1 rules. 186 * It will accept a negative length and place 188 * It will accept a negative length and place a zero length tag 187 * instead (to keep the ASN.1 valid). This co 189 * instead (to keep the ASN.1 valid). This convention allows other 188 * encoder primitives to accept negative lengt 190 * encoder primitives to accept negative lengths as singalling the 189 * sequence will be re-encoded when the length 191 * sequence will be re-encoded when the length is known. 190 */ 192 */ 191 static int asn1_encode_length(unsigned char ** 193 static int asn1_encode_length(unsigned char **data, int *data_len, int len) 192 { 194 { 193 if (*data_len < 1) 195 if (*data_len < 1) 194 return -EINVAL; 196 return -EINVAL; 195 197 196 if (len < 0) { 198 if (len < 0) { 197 *((*data)++) = 0; 199 *((*data)++) = 0; 198 (*data_len)--; 200 (*data_len)--; 199 return 0; 201 return 0; 200 } 202 } 201 203 202 if (len <= 0x7f) { 204 if (len <= 0x7f) { 203 *((*data)++) = len; 205 *((*data)++) = len; 204 (*data_len)--; 206 (*data_len)--; 205 return 0; 207 return 0; 206 } 208 } 207 209 208 if (*data_len < 2) 210 if (*data_len < 2) 209 return -EINVAL; 211 return -EINVAL; 210 212 211 if (len <= 0xff) { 213 if (len <= 0xff) { 212 *((*data)++) = 0x81; 214 *((*data)++) = 0x81; 213 *((*data)++) = len & 0xff; 215 *((*data)++) = len & 0xff; 214 *data_len -= 2; 216 *data_len -= 2; 215 return 0; 217 return 0; 216 } 218 } 217 219 218 if (*data_len < 3) 220 if (*data_len < 3) 219 return -EINVAL; 221 return -EINVAL; 220 222 221 if (len <= 0xffff) { 223 if (len <= 0xffff) { 222 *((*data)++) = 0x82; 224 *((*data)++) = 0x82; 223 *((*data)++) = (len >> 8) & 0x 225 *((*data)++) = (len >> 8) & 0xff; 224 *((*data)++) = len & 0xff; 226 *((*data)++) = len & 0xff; 225 *data_len -= 3; 227 *data_len -= 3; 226 return 0; 228 return 0; 227 } 229 } 228 230 229 if (WARN(len > 0xffffff, "ASN.1 length 231 if (WARN(len > 0xffffff, "ASN.1 length can't be > 0xffffff")) 230 return -EINVAL; 232 return -EINVAL; 231 233 232 if (*data_len < 4) 234 if (*data_len < 4) 233 return -EINVAL; 235 return -EINVAL; 234 *((*data)++) = 0x83; 236 *((*data)++) = 0x83; 235 *((*data)++) = (len >> 16) & 0xff; 237 *((*data)++) = (len >> 16) & 0xff; 236 *((*data)++) = (len >> 8) & 0xff; 238 *((*data)++) = (len >> 8) & 0xff; 237 *((*data)++) = len & 0xff; 239 *((*data)++) = len & 0xff; 238 *data_len -= 4; 240 *data_len -= 4; 239 241 240 return 0; 242 return 0; 241 } 243 } 242 244 243 /** 245 /** 244 * asn1_encode_tag() - add a tag for optional 246 * asn1_encode_tag() - add a tag for optional or explicit value 245 * @data: pointer to place tag at 247 * @data: pointer to place tag at 246 * @end_data: end of data pointer, points on 248 * @end_data: end of data pointer, points one beyond last usable byte in @data 247 * @tag: tag to be placed 249 * @tag: tag to be placed 248 * @string: the data to be tagged 250 * @string: the data to be tagged 249 * @len: the length of the data to be t 251 * @len: the length of the data to be tagged 250 * 252 * 251 * Note this currently only handles short form 253 * Note this currently only handles short form tags < 31. 252 * 254 * 253 * Standard usage is to pass in a @tag, @strin 255 * Standard usage is to pass in a @tag, @string and @length and the 254 * @string will be ASN.1 encoded with @tag and 256 * @string will be ASN.1 encoded with @tag and placed into @data. If 255 * the encoding would put data past @end_data 257 * the encoding would put data past @end_data then an error is 256 * returned, otherwise a pointer to a position 258 * returned, otherwise a pointer to a position one beyond the encoding 257 * is returned. 259 * is returned. 258 * 260 * 259 * To encode in place pass a NULL @string and 261 * To encode in place pass a NULL @string and -1 for @len and the 260 * maximum allowable beginning and end of the 262 * maximum allowable beginning and end of the data; all this will do 261 * is add the current maximum length and updat 263 * is add the current maximum length and update the data pointer to 262 * the place where the tag contents should be 264 * the place where the tag contents should be placed is returned. The 263 * data should be copied in by the calling rou 265 * data should be copied in by the calling routine which should then 264 * repeat the prior statement but now with the 266 * repeat the prior statement but now with the known length. In order 265 * to avoid having to keep both before and aft 267 * to avoid having to keep both before and after pointers, the repeat 266 * expects to be called with @data pointing to 268 * expects to be called with @data pointing to where the first encode 267 * returned it and still NULL for @string but 269 * returned it and still NULL for @string but the real length in @len. 268 */ 270 */ 269 unsigned char * 271 unsigned char * 270 asn1_encode_tag(unsigned char *data, const uns 272 asn1_encode_tag(unsigned char *data, const unsigned char *end_data, 271 u32 tag, const unsigned char * 273 u32 tag, const unsigned char *string, int len) 272 { 274 { 273 int data_len = end_data - data; 275 int data_len = end_data - data; 274 int ret; 276 int ret; 275 277 276 if (WARN(tag > 30, "ASN.1 tag can't be 278 if (WARN(tag > 30, "ASN.1 tag can't be > 30")) 277 return ERR_PTR(-EINVAL); 279 return ERR_PTR(-EINVAL); 278 280 279 if (!string && WARN(len > 127, 281 if (!string && WARN(len > 127, 280 "BUG: recode tag i 282 "BUG: recode tag is too big (>127)")) 281 return ERR_PTR(-EINVAL); 283 return ERR_PTR(-EINVAL); 282 284 283 if (IS_ERR(data)) 285 if (IS_ERR(data)) 284 return data; 286 return data; 285 287 286 if (!string && len > 0) { 288 if (!string && len > 0) { 287 /* 289 /* 288 * we're recoding, so move bac 290 * we're recoding, so move back to the start of the 289 * tag and install a dummy len 291 * tag and install a dummy length because the real 290 * data_len should be NULL 292 * data_len should be NULL 291 */ 293 */ 292 data -= 2; 294 data -= 2; 293 data_len = 2; 295 data_len = 2; 294 } 296 } 295 297 296 if (data_len < 2) 298 if (data_len < 2) 297 return ERR_PTR(-EINVAL); 299 return ERR_PTR(-EINVAL); 298 300 299 *(data++) = _tagn(CONT, CONS, tag); 301 *(data++) = _tagn(CONT, CONS, tag); 300 data_len--; 302 data_len--; 301 ret = asn1_encode_length(&data, &data_ 303 ret = asn1_encode_length(&data, &data_len, len); 302 if (ret < 0) 304 if (ret < 0) 303 return ERR_PTR(ret); 305 return ERR_PTR(ret); 304 306 305 if (!string) 307 if (!string) 306 return data; 308 return data; 307 309 308 if (data_len < len) 310 if (data_len < len) 309 return ERR_PTR(-EINVAL); 311 return ERR_PTR(-EINVAL); 310 312 311 memcpy(data, string, len); 313 memcpy(data, string, len); 312 data += len; 314 data += len; 313 315 314 return data; 316 return data; 315 } 317 } 316 EXPORT_SYMBOL_GPL(asn1_encode_tag); 318 EXPORT_SYMBOL_GPL(asn1_encode_tag); 317 319 318 /** 320 /** 319 * asn1_encode_octet_string() - encode an ASN. 321 * asn1_encode_octet_string() - encode an ASN.1 OCTET STRING 320 * @data: pointer to encode at 322 * @data: pointer to encode at 321 * @end_data: end of data pointer, points on 323 * @end_data: end of data pointer, points one beyond last usable byte in @data 322 * @string: string to be encoded 324 * @string: string to be encoded 323 * @len: length of string 325 * @len: length of string 324 * 326 * 325 * Note ASN.1 octet strings may contain zeros, 327 * Note ASN.1 octet strings may contain zeros, so the length is obligatory. 326 */ 328 */ 327 unsigned char * 329 unsigned char * 328 asn1_encode_octet_string(unsigned char *data, 330 asn1_encode_octet_string(unsigned char *data, 329 const unsigned char * 331 const unsigned char *end_data, 330 const unsigned char * 332 const unsigned char *string, u32 len) 331 { 333 { 332 int data_len = end_data - data; 334 int data_len = end_data - data; 333 int ret; 335 int ret; 334 336 335 if (IS_ERR(data)) 337 if (IS_ERR(data)) 336 return data; 338 return data; 337 339 338 /* need minimum of 2 bytes for tag and 340 /* need minimum of 2 bytes for tag and length of zero length string */ 339 if (data_len < 2) 341 if (data_len < 2) 340 return ERR_PTR(-EINVAL); 342 return ERR_PTR(-EINVAL); 341 343 342 *(data++) = _tag(UNIV, PRIM, OTS); 344 *(data++) = _tag(UNIV, PRIM, OTS); 343 data_len--; 345 data_len--; 344 346 345 ret = asn1_encode_length(&data, &data_ 347 ret = asn1_encode_length(&data, &data_len, len); 346 if (ret) 348 if (ret) 347 return ERR_PTR(ret); 349 return ERR_PTR(ret); 348 350 349 if (data_len < len) 351 if (data_len < len) 350 return ERR_PTR(-EINVAL); 352 return ERR_PTR(-EINVAL); 351 353 352 memcpy(data, string, len); 354 memcpy(data, string, len); 353 data += len; 355 data += len; 354 356 355 return data; 357 return data; 356 } 358 } 357 EXPORT_SYMBOL_GPL(asn1_encode_octet_string); 359 EXPORT_SYMBOL_GPL(asn1_encode_octet_string); 358 360 359 /** 361 /** 360 * asn1_encode_sequence() - wrap a byte stream 362 * asn1_encode_sequence() - wrap a byte stream in an ASN.1 SEQUENCE 361 * @data: pointer to encode at 363 * @data: pointer to encode at 362 * @end_data: end of data pointer, points on 364 * @end_data: end of data pointer, points one beyond last usable byte in @data 363 * @seq: data to be encoded as a sequen 365 * @seq: data to be encoded as a sequence 364 * @len: length of the data to be encod 366 * @len: length of the data to be encoded as a sequence 365 * 367 * 366 * Fill in a sequence. To encode in place, pa 368 * Fill in a sequence. To encode in place, pass NULL for @seq and -1 367 * for @len; then call again once the length i 369 * for @len; then call again once the length is known (still with NULL 368 * for @seq). In order to avoid having to keep 370 * for @seq). In order to avoid having to keep both before and after 369 * pointers, the repeat expects to be called w 371 * pointers, the repeat expects to be called with @data pointing to 370 * where the first encode placed it. 372 * where the first encode placed it. 371 */ 373 */ 372 unsigned char * 374 unsigned char * 373 asn1_encode_sequence(unsigned char *data, cons 375 asn1_encode_sequence(unsigned char *data, const unsigned char *end_data, 374 const unsigned char *seq, 376 const unsigned char *seq, int len) 375 { 377 { 376 int data_len = end_data - data; 378 int data_len = end_data - data; 377 int ret; 379 int ret; 378 380 379 if (!seq && WARN(len > 127, 381 if (!seq && WARN(len > 127, 380 "BUG: recode sequence 382 "BUG: recode sequence is too big (>127)")) 381 return ERR_PTR(-EINVAL); 383 return ERR_PTR(-EINVAL); 382 384 383 if (IS_ERR(data)) 385 if (IS_ERR(data)) 384 return data; 386 return data; 385 387 386 if (!seq && len >= 0) { 388 if (!seq && len >= 0) { 387 /* 389 /* 388 * we're recoding, so move bac 390 * we're recoding, so move back to the start of the 389 * sequence and install a dumm 391 * sequence and install a dummy length because the 390 * real length should be NULL 392 * real length should be NULL 391 */ 393 */ 392 data -= 2; 394 data -= 2; 393 data_len = 2; 395 data_len = 2; 394 } 396 } 395 397 396 if (data_len < 2) 398 if (data_len < 2) 397 return ERR_PTR(-EINVAL); 399 return ERR_PTR(-EINVAL); 398 400 399 *(data++) = _tag(UNIV, CONS, SEQ); 401 *(data++) = _tag(UNIV, CONS, SEQ); 400 data_len--; 402 data_len--; 401 403 402 ret = asn1_encode_length(&data, &data_ 404 ret = asn1_encode_length(&data, &data_len, len); 403 if (ret) 405 if (ret) 404 return ERR_PTR(ret); 406 return ERR_PTR(ret); 405 407 406 if (!seq) 408 if (!seq) 407 return data; 409 return data; 408 410 409 if (data_len < len) 411 if (data_len < len) 410 return ERR_PTR(-EINVAL); 412 return ERR_PTR(-EINVAL); 411 413 412 memcpy(data, seq, len); 414 memcpy(data, seq, len); 413 data += len; 415 data += len; 414 416 415 return data; 417 return data; 416 } 418 } 417 EXPORT_SYMBOL_GPL(asn1_encode_sequence); 419 EXPORT_SYMBOL_GPL(asn1_encode_sequence); 418 420 419 /** 421 /** 420 * asn1_encode_boolean() - encode a boolean va 422 * asn1_encode_boolean() - encode a boolean value to ASN.1 421 * @data: pointer to encode at 423 * @data: pointer to encode at 422 * @end_data: end of data pointer, points on 424 * @end_data: end of data pointer, points one beyond last usable byte in @data 423 * @val: the boolean true/false value 425 * @val: the boolean true/false value 424 */ 426 */ 425 unsigned char * 427 unsigned char * 426 asn1_encode_boolean(unsigned char *data, const 428 asn1_encode_boolean(unsigned char *data, const unsigned char *end_data, 427 bool val) 429 bool val) 428 { 430 { 429 int data_len = end_data - data; 431 int data_len = end_data - data; 430 432 431 if (IS_ERR(data)) 433 if (IS_ERR(data)) 432 return data; 434 return data; 433 435 434 /* booleans are 3 bytes: tag, length = 436 /* booleans are 3 bytes: tag, length == 1 and value == 0 or 1 */ 435 if (data_len < 3) 437 if (data_len < 3) 436 return ERR_PTR(-EINVAL); 438 return ERR_PTR(-EINVAL); 437 439 438 *(data++) = _tag(UNIV, PRIM, BOOL); 440 *(data++) = _tag(UNIV, PRIM, BOOL); 439 data_len--; 441 data_len--; 440 442 441 asn1_encode_length(&data, &data_len, 1 443 asn1_encode_length(&data, &data_len, 1); 442 444 443 if (val) 445 if (val) 444 *(data++) = 1; 446 *(data++) = 1; 445 else 447 else 446 *(data++) = 0; 448 *(data++) = 0; 447 449 448 return data; 450 return data; 449 } 451 } 450 EXPORT_SYMBOL_GPL(asn1_encode_boolean); 452 EXPORT_SYMBOL_GPL(asn1_encode_boolean); 451 453 452 MODULE_DESCRIPTION("Simple encoder primitives << 453 MODULE_LICENSE("GPL"); 454 MODULE_LICENSE("GPL"); 454 455
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.