blob: 7981727b6672848b21c29ac1f7a48abf0254082c [file] [log] [blame]
Jeff Thompsona92861a2013-10-16 14:06:23 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/**
3 * Copyright (C) 2013 Regents of the University of California.
4 * @author: Yingdi Yu <yingdi@cs.ucla.edu>
5 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
6 * See COPYING for copyright and distribution information.
7 */
8
9#if 1 // TODO: Remove this when we don't throw "not implemented".
10#include <stdexcept>
11#endif
12#include "der-exception.hpp"
13#include "../../util/logging.hpp"
14#include "der.hpp"
15
16INIT_LOGGER("ndn.der.DER");
17
18using namespace std;
19using namespace ndn::ptr_lib;
20
21namespace ndn {
22
23namespace der {
24
25/*
26 * DerNode
27 */
28DerNode::DerNode()
Jeff Thompson7ff36fe2013-10-16 15:30:13 -070029 :parent_(0)
Jeff Thompsona92861a2013-10-16 14:06:23 -070030{}
31
32DerNode::DerNode(DerType type)
Jeff Thompson7ff36fe2013-10-16 15:30:13 -070033 :type_(type),
34 parent_(0)
Jeff Thompsona92861a2013-10-16 14:06:23 -070035{}
36
37DerNode::DerNode(std::istream& start)
Jeff Thompson7ff36fe2013-10-16 15:30:13 -070038 :parent_(0)
Jeff Thompsona92861a2013-10-16 14:06:23 -070039{
40 decode(start);
41}
42
43DerNode::~DerNode()
44{}
45
46void
47DerNode::encodeHeader(int size)
48{
Jeff Thompson7ff36fe2013-10-16 15:30:13 -070049 header_.push_back((char)type_);
Jeff Thompsona92861a2013-10-16 14:06:23 -070050
Jeff Thompson161a2e02013-10-16 16:04:08 -070051 if (size >= 127) {
52 int val = size;
53 char buf[sizeof(val) + 1];
54 char *p = &(buf[sizeof(buf)-1]);
55 int n = 0;
56 int mask = (1 << 8) - 1;
Jeff Thompsona92861a2013-10-16 14:06:23 -070057
Jeff Thompson161a2e02013-10-16 16:04:08 -070058 while (val != 0) {
59 p[0] = (char)(val & mask);
60 p--;
Jeff Thompsona92861a2013-10-16 14:06:23 -070061 n++;
Jeff Thompson161a2e02013-10-16 16:04:08 -070062 val >>= 8;
63 }
Jeff Thompsona92861a2013-10-16 14:06:23 -070064
Jeff Thompson161a2e02013-10-16 16:04:08 -070065 p[0] = (char)((1<<7) | n);
66 n++;
67
68 header_.insert(header_.end(), p, p+n);
69 }
70 else if (size >= 0)
71 header_.push_back((char)size);
Jeff Thompsona92861a2013-10-16 14:06:23 -070072 else
73 throw NegativeLengthException("Negative length");
74}
75
76int
77DerNode::decodeHeader(istream& start)
78{
79 uint8_t type = start.get();
80 // char type = start.get();
Jeff Thompson7ff36fe2013-10-16 15:30:13 -070081 header_.push_back(type);
82 type_ = static_cast<DerType>((int)type);
Jeff Thompsona92861a2013-10-16 14:06:23 -070083
84 uint8_t sizeLen = start.get();
85 // char sizeLen = start.get();
Jeff Thompson7ff36fe2013-10-16 15:30:13 -070086 header_.push_back(sizeLen);
Jeff Thompsona92861a2013-10-16 14:06:23 -070087
88 bool longFormat = sizeLen & (1 << 7);
89
Jeff Thompson161a2e02013-10-16 16:04:08 -070090 if (!longFormat) {
91 // _LOG_DEBUG("Short Format");
92 // _LOG_DEBUG("sizeLen: " << (int)sizeLen);
93 return (int)sizeLen;
94 }
95 else {
96 // _LOG_DEBUG("Long Format");
97 uint8_t byte;
98 // char byte;
99 int lenCount = sizeLen & ((1<<7) - 1);
100 // _LOG_DEBUG("sizeLen: " << (int)sizeLen);
101 // _LOG_DEBUG("mask: " << (int)((1<<7) - 1));
102 // _LOG_DEBUG("lenCount: " << (int)lenCount);
103 int size = 0;
104 do {
105 byte = start.get();
106 header_.push_back(byte);
107 size = size * 256 + (int)byte;
108 // _LOG_DEBUG("byte: " << (int)byte);
109 // _LOG_DEBUG("size: " << size);
110 lenCount--;
111 } while (lenCount > 0);
Jeff Thompsona92861a2013-10-16 14:06:23 -0700112
Jeff Thompson161a2e02013-10-16 16:04:08 -0700113 return size;
114 }
Jeff Thompsona92861a2013-10-16 14:06:23 -0700115}
116
117void
118DerNode::encode(ostream& start)
119{
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700120 start.write((const char*)&header_[0], header_.size());
121 start.write((const char*)&payload_[0], payload_.size());
Jeff Thompsona92861a2013-10-16 14:06:23 -0700122}
123
124void
125DerNode::decode(istream& start)
126{
127 int payloadSize = decodeHeader(start);
128 // _LOG_DEBUG("payloadSize: " << payloadSize);
Jeff Thompson161a2e02013-10-16 16:04:08 -0700129 if (payloadSize > 0 ) {
130 char buf[payloadSize];
131 start.read(buf, payloadSize);
132 payload_.insert(payload_.end(), buf, buf + payloadSize);
133 }
Jeff Thompsona92861a2013-10-16 14:06:23 -0700134}
135
136shared_ptr<DerNode>
137DerNode::parse(istream& start)
138{
139 int type = ((uint8_t)start.peek());
140
141 // _LOG_DEBUG("Type: " << hex << setw(2) << setfill('0') << type);
142 switch(type) {
143 case DER_BOOLEAN:
144 return shared_ptr<DerBool>(new DerBool(start));
145 case DER_INTEGER:
146 return shared_ptr<DerInteger>(new DerInteger(start));
147 case DER_BIT_STRING:
148 return shared_ptr<DerBitString>(new DerBitString(start));
149 case DER_OCTET_STRING:
150 return shared_ptr<DerOctetString>(new DerOctetString(start));
151 case DER_NULL:
152 return shared_ptr<DerNull>(new DerNull(start));
153 case DER_OBJECT_IDENTIFIER:
154 return shared_ptr<DerOid>(new DerOid(start));
155 case DER_SEQUENCE:
156 return shared_ptr<DerSequence>(new DerSequence(start));
157 case DER_PRINTABLE_STRING:
158 return shared_ptr<DerPrintableString>(new DerPrintableString(start));
159 case DER_GENERALIZED_TIME:
160 return shared_ptr<DerGtime>(new DerGtime(start));
161 default:
162 throw DerDecodingException("Unimplemented DER types");
Jeff Thompson161a2e02013-10-16 16:04:08 -0700163 }
Jeff Thompsona92861a2013-10-16 14:06:23 -0700164}
165
166
167/*
168 * DerComplex
169 */
170DerComplex::DerComplex()
171 :DerNode(),
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700172 childChanged_(false),
173 size_(0)
Jeff Thompsona92861a2013-10-16 14:06:23 -0700174{}
175
176DerComplex::DerComplex(DerType type)
177 :DerNode(type),
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700178 childChanged_(false),
179 size_(0)
Jeff Thompsona92861a2013-10-16 14:06:23 -0700180{}
181
182DerComplex::DerComplex(istream& start)
183 :DerNode(),
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700184 childChanged_(false),
185 size_(0)
Jeff Thompsona92861a2013-10-16 14:06:23 -0700186{
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700187 size_ = DerNode::decodeHeader(start);
188 // _LOG_DEBUG("Size: " << size_);
Jeff Thompsona92861a2013-10-16 14:06:23 -0700189
190 int accSize = 0;
191
Jeff Thompson161a2e02013-10-16 16:04:08 -0700192 while (accSize < size_) {
193 // _LOG_DEBUG("accSize: " << accSize);
194 shared_ptr<DerNode> nodePtr = DerNode::parse(start);
195 accSize += nodePtr->getSize();
196 addChild(nodePtr, false);
197 }
Jeff Thompsona92861a2013-10-16 14:06:23 -0700198}
199
200DerComplex::~DerComplex()
201{}
202
203int
204DerComplex::getSize()
205{
Jeff Thompson161a2e02013-10-16 16:04:08 -0700206 if (childChanged_) {
207 updateSize();
208 childChanged_ = false;
209 }
Jeff Thompsona92861a2013-10-16 14:06:23 -0700210
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700211 header_.clear();
212 DerNode::encodeHeader(size_);
213 return size_ + header_.size();
Jeff Thompsona92861a2013-10-16 14:06:23 -0700214}
215
216shared_ptr<vector<uint8_t> >
217DerComplex::getRaw()
218{
219 shared_ptr<vector<uint8_t> > blob(new vector<uint8_t>());
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700220 blob->insert(blob->end(), header_.begin(), header_.end());
Jeff Thompsona92861a2013-10-16 14:06:23 -0700221
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700222 DerNodePtrList::iterator it = nodeList_.begin();
Jeff Thompson161a2e02013-10-16 16:04:08 -0700223 for (; it != nodeList_.end(); it++) {
224 shared_ptr<vector<uint8_t> > childBlob = (*it)->getRaw();
225 blob->insert(blob->end(), childBlob->begin(), childBlob->end());
226 }
Jeff Thompsona92861a2013-10-16 14:06:23 -0700227 return blob;
228}
229
230void
231DerComplex::updateSize()
232{
233 int newSize = 0;
234
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700235 DerNodePtrList::iterator it = nodeList_.begin();
Jeff Thompson161a2e02013-10-16 16:04:08 -0700236 for (; it != nodeList_.end(); it++) {
237 newSize += (*it)->getSize();
238 }
Jeff Thompsona92861a2013-10-16 14:06:23 -0700239
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700240 size_ = newSize;
241 childChanged_ = false;
Jeff Thompsona92861a2013-10-16 14:06:23 -0700242}
243
244void
245DerComplex::addChild(shared_ptr<DerNode> nodePtr, bool notifyParent)
246{
247 nodePtr->setParent(this);
248
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700249 nodeList_.push_back(nodePtr);
Jeff Thompsona92861a2013-10-16 14:06:23 -0700250
Jeff Thompson161a2e02013-10-16 16:04:08 -0700251 if (!notifyParent)
Jeff Thompsona92861a2013-10-16 14:06:23 -0700252 return;
253
Jeff Thompson161a2e02013-10-16 16:04:08 -0700254 if (childChanged_)
Jeff Thompsona92861a2013-10-16 14:06:23 -0700255 return;
256 else
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700257 childChanged_ = true;
Jeff Thompsona92861a2013-10-16 14:06:23 -0700258
Jeff Thompson161a2e02013-10-16 16:04:08 -0700259 if (0 != parent_)
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700260 parent_->setChildChanged();
Jeff Thompsona92861a2013-10-16 14:06:23 -0700261}
262
263void
264DerComplex::setChildChanged()
265{
Jeff Thompson161a2e02013-10-16 16:04:08 -0700266 if (0 != parent_ && !childChanged_) {
267 parent_->setChildChanged();
268 childChanged_ = true;
269 }
Jeff Thompsona92861a2013-10-16 14:06:23 -0700270 else
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700271 childChanged_ = true;
Jeff Thompsona92861a2013-10-16 14:06:23 -0700272}
273
274void
275DerComplex::encode(ostream& start)
276{
277 updateSize();
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700278 header_.clear();
Jeff Thompsona92861a2013-10-16 14:06:23 -0700279
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700280 DerNode::encodeHeader(size_);
Jeff Thompsona92861a2013-10-16 14:06:23 -0700281
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700282 start.write((const char*)&header_[0], header_.size());
Jeff Thompsona92861a2013-10-16 14:06:23 -0700283
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700284 DerNodePtrList::iterator it = nodeList_.begin();
Jeff Thompson161a2e02013-10-16 16:04:08 -0700285 for (; it != nodeList_.end(); it++)
Jeff Thompsona92861a2013-10-16 14:06:23 -0700286 (*it)->encode(start);
287}
288
289
290/*
291 * DerByteString
292 */
293DerByteString::DerByteString(const string& str, DerType type)
294 :DerNode(type)
295{
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700296 payload_.insert(payload_.end(), str.begin(), str.end());
Jeff Thompsona92861a2013-10-16 14:06:23 -0700297
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700298 DerNode::encodeHeader(payload_.size());
Jeff Thompsona92861a2013-10-16 14:06:23 -0700299}
300
301DerByteString::DerByteString(const std::vector<uint8_t>& blob, DerType type)
302 :DerNode(type)
303{
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700304 payload_.insert(payload_.end(), blob.begin(), blob.end());
Jeff Thompsona92861a2013-10-16 14:06:23 -0700305
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700306 DerNode::encodeHeader(payload_.size());
Jeff Thompsona92861a2013-10-16 14:06:23 -0700307}
308
309DerByteString::DerByteString(istream& start)
310 :DerNode(start)
311{}
312
313DerByteString::~DerByteString()
314{}
315
316
317/*
318 * DerBool
319 */
320DerBool::DerBool(bool value)
321 :DerNode(DER_BOOLEAN)
322
323{
324 char payload = (value ? 0xFF : 0x00);
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700325 payload_.push_back(payload);
Jeff Thompsona92861a2013-10-16 14:06:23 -0700326
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700327 DerNode::encodeHeader(payload_.size());
Jeff Thompsona92861a2013-10-16 14:06:23 -0700328}
329
330DerBool::DerBool(istream& start)
331 :DerNode(start)
332{}
333
334DerBool::~DerBool()
335{}
336
337
338/*
339 * DerInteger
340 */
341DerInteger::DerInteger(const vector<uint8_t>& blob)
342 :DerNode(DER_INTEGER)
343{
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700344 payload_.insert(payload_.end(), blob.begin(), blob.end());
Jeff Thompsona92861a2013-10-16 14:06:23 -0700345
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700346 DerNode::encodeHeader(payload_.size());
Jeff Thompsona92861a2013-10-16 14:06:23 -0700347}
348
349DerInteger::DerInteger(istream& start)
350 :DerNode(start)
351{}
352
353DerInteger::~DerInteger()
354{}
355
356
357/*
358 * DerBitString
359 */
360DerBitString::DerBitString(const vector<uint8_t>& blob, uint8_t paddingLen)
361 :DerNode(DER_BIT_STRING)
362{
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700363 payload_.push_back((char)paddingLen);
364 payload_.insert(payload_.end(), blob.begin(), blob.end());
Jeff Thompsona92861a2013-10-16 14:06:23 -0700365
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700366 DerNode::encodeHeader(payload_.size());
Jeff Thompsona92861a2013-10-16 14:06:23 -0700367}
368
369DerBitString::DerBitString(istream& start)
370 :DerNode(start)
371{}
372
373DerBitString::~DerBitString()
374{}
375
376
377/*
378 * DerOctetString
379 */
380DerOctetString::DerOctetString(const string& str)
381 :DerByteString(str, DER_OCTET_STRING)
382{}
383
384DerOctetString::DerOctetString(const vector<uint8_t>& blob)
385 :DerByteString(blob, DER_OCTET_STRING)
386{}
387
388DerOctetString::DerOctetString(istream& start)
389 :DerByteString(start)
390{}
391
392DerOctetString::~DerOctetString()
393{}
394
395
396/*
397 * DerNull
398 */
399DerNull::DerNull()
400 :DerNode(DER_NULL)
401{
402 DerNode::encodeHeader(0);
403}
404
405DerNull::DerNull(istream& start)
406 :DerNode(start)
407{}
408
409DerNull::~DerNull()
410{}
411
412
413/*
414 * DerOid
415 */
416DerOid::DerOid(const OID& oid)
417 :DerNode(DER_OBJECT_IDENTIFIER)
418{
419 prepareEncoding(oid.getIntegerList());
420}
421
422
423DerOid::DerOid(const string& oidStr)
424 :DerNode(DER_OBJECT_IDENTIFIER)
425{
426 vector<int> value;
427
428 string str = oidStr + ".";
429
430 size_t pos = 0;
431 size_t ppos = 0;
432
Jeff Thompson161a2e02013-10-16 16:04:08 -0700433 while (string::npos != pos) {
Jeff Thompsona92861a2013-10-16 14:06:23 -0700434 ppos = pos;
435
436 pos = str.find_first_of('.', pos);
Jeff Thompson161a2e02013-10-16 16:04:08 -0700437 if (string::npos == pos)
438 break;
Jeff Thompsona92861a2013-10-16 14:06:23 -0700439
440 value.push_back(atoi(str.substr(ppos, pos - ppos).c_str()));
441
442 pos++;
443 }
444
445 prepareEncoding(value);
446}
447
448DerOid::DerOid(const vector<int>& value)
449 :DerNode(DER_OBJECT_IDENTIFIER)
450{
451 prepareEncoding(value);
452}
453
454DerOid::DerOid(istream& start)
455 :DerNode(start)
456{}
457
458DerOid::~DerOid()
459{}
460
461void
462DerOid::prepareEncoding(const vector<int>& value)
463{
464 ostringstream os;
465
466 int firstNumber = 0;
467
Jeff Thompson161a2e02013-10-16 16:04:08 -0700468 if (value.size() >= 1) {
469 if (0 <= value[0] && 2 >= value[0])
470 firstNumber = value[0] * 40;
Jeff Thompsona92861a2013-10-16 14:06:23 -0700471 else
Jeff Thompson161a2e02013-10-16 16:04:08 -0700472 throw DerEncodingException("first integer of oid is out of range");
Jeff Thompsona92861a2013-10-16 14:06:23 -0700473 }
474 else
475 throw DerEncodingException("no integer in oid");
476
Jeff Thompson161a2e02013-10-16 16:04:08 -0700477 if (value.size() >= 2) {
478 if (0 <= value[1] && 39 >= value[1])
479 firstNumber += value[1];
Jeff Thompsona92861a2013-10-16 14:06:23 -0700480 else
Jeff Thompson161a2e02013-10-16 16:04:08 -0700481 throw DerEncodingException("second integer of oid is out of range");
Jeff Thompsona92861a2013-10-16 14:06:23 -0700482 }
483
484 encode128(firstNumber, os);
485
Jeff Thompson161a2e02013-10-16 16:04:08 -0700486 if (value.size() > 2) {
Jeff Thompsona92861a2013-10-16 14:06:23 -0700487 int i = 2;
Jeff Thompson161a2e02013-10-16 16:04:08 -0700488 for (; i < value.size(); i++)
489 encode128(value[i], os);
Jeff Thompsona92861a2013-10-16 14:06:23 -0700490 }
491
492 string output = os.str();
493 DerNode::encodeHeader(output.size());
494
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700495 payload_.insert(payload_.end(), output.begin(), output.end());
Jeff Thompsona92861a2013-10-16 14:06:23 -0700496}
497
498void
499DerOid::encode128(int value, ostringstream& os)
500{
501 int mask = (1 << 7) - 1;
502
Jeff Thompson161a2e02013-10-16 16:04:08 -0700503 if (128 > value) {
504 uint8_t singleByte = (uint8_t) mask & value;
505 os.write((char *)&singleByte, 1);
506 }
507 else {
Jeff Thompsona92861a2013-10-16 14:06:23 -0700508 uint8_t buf[(sizeof(value)*8 + 6)/7 + 1];
509 uint8_t *p = &(buf[sizeof(buf)-1]);
510 int n = 1;
511
512 p[0] = (uint8_t)(value & mask);
513 value >>= 7;
514
Jeff Thompson161a2e02013-10-16 16:04:08 -0700515 while (value != 0) {
516 (--p)[0] = (uint8_t)((value & mask) | (1 << 7));
517 n++;
518 value >>= 7;
519 }
Jeff Thompsona92861a2013-10-16 14:06:23 -0700520
521 os.write((char *)p, n);
522 }
523}
524
525int
526DerOid::decode128(int & offset)
527{
528 uint8_t flagMask = 0x80;
529 int result = 0;
Jeff Thompson161a2e02013-10-16 16:04:08 -0700530 while (payload_[offset] & flagMask) {
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700531 result = 128 * result + (uint8_t) payload_[offset] - 128;
Jeff Thompsona92861a2013-10-16 14:06:23 -0700532 offset++;
533 }
534
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700535 result = result * 128 + payload_[offset];
Jeff Thompsona92861a2013-10-16 14:06:23 -0700536 offset++;
537
538 return result;
539}
540
541
542/*
543 * DerSequence
544 */
545DerSequence::DerSequence()
546 :DerComplex(DER_SEQUENCE)
547{}
548
549DerSequence::DerSequence(istream& start)
550 :DerComplex(start)
551{}
552
553DerSequence::~DerSequence()
554{}
555
556
557/*
558 * DerPrintableString
559 */
560DerPrintableString::DerPrintableString(const string& str)
561 :DerByteString(str, DER_PRINTABLE_STRING)
562{}
563
564DerPrintableString::DerPrintableString(const vector<uint8_t>& blob)
565 :DerByteString(blob, DER_PRINTABLE_STRING)
566{}
567
568DerPrintableString::DerPrintableString(istream& start)
569 :DerByteString(start)
570{}
571
572DerPrintableString::~DerPrintableString()
573{}
574
575
576/*
577 * DerGtime
578 */
579DerGtime::DerGtime(const Time& time)
580 :DerNode(DER_GENERALIZED_TIME)
581{
582 string pTimeStr = toIsoString(time);
583 int index = pTimeStr.find_first_of('T');
584 string derTime = pTimeStr.substr(0, index) + pTimeStr.substr(index+1, pTimeStr.size() - index -1) + "Z";
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700585 payload_.insert(payload_.end(), derTime.begin(), derTime.end());
Jeff Thompsona92861a2013-10-16 14:06:23 -0700586
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700587 DerNode::encodeHeader(payload_.size());
Jeff Thompsona92861a2013-10-16 14:06:23 -0700588}
589
590DerGtime::DerGtime(istream& start)
591 :DerNode(start)
592{}
593
594DerGtime::~DerGtime()
595{}
596
597string DerGtime::toIsoString(const Time& time)
598{
599#if 1
600 throw std::runtime_error("not implemented");
601#endif
602}
603
604Time DerGtime::fromIsoString(const string& isoString)
605{
606#if 1
607 throw std::runtime_error("not implemented");
608#endif
609}
610
611} // der
612
613}