blob: b9a2f12db2213255e8da885f653ca006e4566671 [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
51 if(size >= 127)
52 {
53 int val = size;
54 char buf[sizeof(val) + 1];
55 char *p = &(buf[sizeof(buf)-1]);
56 int n = 0;
57 int mask = (1 << 8) - 1;
58
59 while(val != 0)
60 {
61 p[0] = (char)(val & mask);
62 p--;
63 n++;
64 val >>= 8;
65 }
66
67 p[0] = (char)((1<<7) | n);
68 n++;
69
Jeff Thompson7ff36fe2013-10-16 15:30:13 -070070 header_.insert(header_.end(), p, p+n);
Jeff Thompsona92861a2013-10-16 14:06:23 -070071 }
72 else if(size >= 0)
73 {
Jeff Thompson7ff36fe2013-10-16 15:30:13 -070074 header_.push_back((char)size);
Jeff Thompsona92861a2013-10-16 14:06:23 -070075 }
76 else
77 throw NegativeLengthException("Negative length");
78}
79
80int
81DerNode::decodeHeader(istream& start)
82{
83 uint8_t type = start.get();
84 // char type = start.get();
Jeff Thompson7ff36fe2013-10-16 15:30:13 -070085 header_.push_back(type);
86 type_ = static_cast<DerType>((int)type);
Jeff Thompsona92861a2013-10-16 14:06:23 -070087
88 uint8_t sizeLen = start.get();
89 // char sizeLen = start.get();
Jeff Thompson7ff36fe2013-10-16 15:30:13 -070090 header_.push_back(sizeLen);
Jeff Thompsona92861a2013-10-16 14:06:23 -070091
92 bool longFormat = sizeLen & (1 << 7);
93
94 if(!longFormat)
95 {
96 // _LOG_DEBUG("Short Format");
97 // _LOG_DEBUG("sizeLen: " << (int)sizeLen);
98 return (int)sizeLen;
99 }
100 else
101 {
102 // _LOG_DEBUG("Long Format");
103 uint8_t byte;
104 // char byte;
105 int lenCount = sizeLen & ((1<<7) - 1);
106 // _LOG_DEBUG("sizeLen: " << (int)sizeLen);
107 // _LOG_DEBUG("mask: " << (int)((1<<7) - 1));
108 // _LOG_DEBUG("lenCount: " << (int)lenCount);
109 int size = 0;
110 do
111 {
112 byte = start.get();
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700113 header_.push_back(byte);
Jeff Thompsona92861a2013-10-16 14:06:23 -0700114 size = size * 256 + (int)byte;
115 // _LOG_DEBUG("byte: " << (int)byte);
116 // _LOG_DEBUG("size: " << size);
117 lenCount--;
118 }
119 while(lenCount > 0);
120
121 return size;
122 }
123}
124
125void
126DerNode::encode(ostream& start)
127{
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700128 start.write((const char*)&header_[0], header_.size());
129 start.write((const char*)&payload_[0], payload_.size());
Jeff Thompsona92861a2013-10-16 14:06:23 -0700130}
131
132void
133DerNode::decode(istream& start)
134{
135 int payloadSize = decodeHeader(start);
136 // _LOG_DEBUG("payloadSize: " << payloadSize);
137 if(payloadSize > 0 )
138 {
139 char buf[payloadSize];
140 start.read(buf, payloadSize);
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700141 payload_.insert(payload_.end(), buf, buf + payloadSize);
Jeff Thompsona92861a2013-10-16 14:06:23 -0700142 }
143}
144
145shared_ptr<DerNode>
146DerNode::parse(istream& start)
147{
148 int type = ((uint8_t)start.peek());
149
150 // _LOG_DEBUG("Type: " << hex << setw(2) << setfill('0') << type);
151 switch(type) {
152 case DER_BOOLEAN:
153 return shared_ptr<DerBool>(new DerBool(start));
154 case DER_INTEGER:
155 return shared_ptr<DerInteger>(new DerInteger(start));
156 case DER_BIT_STRING:
157 return shared_ptr<DerBitString>(new DerBitString(start));
158 case DER_OCTET_STRING:
159 return shared_ptr<DerOctetString>(new DerOctetString(start));
160 case DER_NULL:
161 return shared_ptr<DerNull>(new DerNull(start));
162 case DER_OBJECT_IDENTIFIER:
163 return shared_ptr<DerOid>(new DerOid(start));
164 case DER_SEQUENCE:
165 return shared_ptr<DerSequence>(new DerSequence(start));
166 case DER_PRINTABLE_STRING:
167 return shared_ptr<DerPrintableString>(new DerPrintableString(start));
168 case DER_GENERALIZED_TIME:
169 return shared_ptr<DerGtime>(new DerGtime(start));
170 default:
171 throw DerDecodingException("Unimplemented DER types");
172 }
173}
174
175
176/*
177 * DerComplex
178 */
179DerComplex::DerComplex()
180 :DerNode(),
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700181 childChanged_(false),
182 size_(0)
Jeff Thompsona92861a2013-10-16 14:06:23 -0700183{}
184
185DerComplex::DerComplex(DerType type)
186 :DerNode(type),
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700187 childChanged_(false),
188 size_(0)
Jeff Thompsona92861a2013-10-16 14:06:23 -0700189{}
190
191DerComplex::DerComplex(istream& start)
192 :DerNode(),
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700193 childChanged_(false),
194 size_(0)
Jeff Thompsona92861a2013-10-16 14:06:23 -0700195{
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700196 size_ = DerNode::decodeHeader(start);
197 // _LOG_DEBUG("Size: " << size_);
Jeff Thompsona92861a2013-10-16 14:06:23 -0700198
199 int accSize = 0;
200
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700201 while(accSize < size_)
Jeff Thompsona92861a2013-10-16 14:06:23 -0700202 {
203 // _LOG_DEBUG("accSize: " << accSize);
204 shared_ptr<DerNode> nodePtr = DerNode::parse(start);
205 accSize += nodePtr->getSize();
206 addChild(nodePtr, false);
207 }
208}
209
210DerComplex::~DerComplex()
211{}
212
213int
214DerComplex::getSize()
215{
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700216 if(childChanged_)
Jeff Thompsona92861a2013-10-16 14:06:23 -0700217 {
218 updateSize();
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700219 childChanged_ = false;
Jeff Thompsona92861a2013-10-16 14:06:23 -0700220 }
221
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700222 header_.clear();
223 DerNode::encodeHeader(size_);
224 return size_ + header_.size();
Jeff Thompsona92861a2013-10-16 14:06:23 -0700225}
226
227shared_ptr<vector<uint8_t> >
228DerComplex::getRaw()
229{
230 shared_ptr<vector<uint8_t> > blob(new vector<uint8_t>());
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700231 blob->insert(blob->end(), header_.begin(), header_.end());
Jeff Thompsona92861a2013-10-16 14:06:23 -0700232
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700233 DerNodePtrList::iterator it = nodeList_.begin();
234 for(; it != nodeList_.end(); it++)
Jeff Thompsona92861a2013-10-16 14:06:23 -0700235 {
236 shared_ptr<vector<uint8_t> > childBlob = (*it)->getRaw();
237 blob->insert(blob->end(), childBlob->begin(), childBlob->end());
238 }
239 return blob;
240}
241
242void
243DerComplex::updateSize()
244{
245 int newSize = 0;
246
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700247 DerNodePtrList::iterator it = nodeList_.begin();
248 for(; it != nodeList_.end(); it++)
Jeff Thompsona92861a2013-10-16 14:06:23 -0700249 {
250 newSize += (*it)->getSize();
251 }
252
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700253 size_ = newSize;
254 childChanged_ = false;
Jeff Thompsona92861a2013-10-16 14:06:23 -0700255}
256
257void
258DerComplex::addChild(shared_ptr<DerNode> nodePtr, bool notifyParent)
259{
260 nodePtr->setParent(this);
261
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700262 nodeList_.push_back(nodePtr);
Jeff Thompsona92861a2013-10-16 14:06:23 -0700263
264 if(!notifyParent)
265 return;
266
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700267 if(childChanged_)
Jeff Thompsona92861a2013-10-16 14:06:23 -0700268 return;
269 else
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700270 childChanged_ = true;
Jeff Thompsona92861a2013-10-16 14:06:23 -0700271
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700272 if(0 != parent_)
273 parent_->setChildChanged();
Jeff Thompsona92861a2013-10-16 14:06:23 -0700274}
275
276void
277DerComplex::setChildChanged()
278{
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700279 if(0 != parent_ && !childChanged_)
Jeff Thompsona92861a2013-10-16 14:06:23 -0700280 {
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700281 parent_->setChildChanged();
282 childChanged_ = true;
Jeff Thompsona92861a2013-10-16 14:06:23 -0700283 }
284 else
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700285 childChanged_ = true;
Jeff Thompsona92861a2013-10-16 14:06:23 -0700286}
287
288void
289DerComplex::encode(ostream& start)
290{
291 updateSize();
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700292 header_.clear();
Jeff Thompsona92861a2013-10-16 14:06:23 -0700293
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700294 DerNode::encodeHeader(size_);
Jeff Thompsona92861a2013-10-16 14:06:23 -0700295
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700296 start.write((const char*)&header_[0], header_.size());
Jeff Thompsona92861a2013-10-16 14:06:23 -0700297
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700298 DerNodePtrList::iterator it = nodeList_.begin();
299 for(; it != nodeList_.end(); it++)
Jeff Thompsona92861a2013-10-16 14:06:23 -0700300 (*it)->encode(start);
301}
302
303
304/*
305 * DerByteString
306 */
307DerByteString::DerByteString(const string& str, DerType type)
308 :DerNode(type)
309{
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700310 payload_.insert(payload_.end(), str.begin(), str.end());
Jeff Thompsona92861a2013-10-16 14:06:23 -0700311
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700312 DerNode::encodeHeader(payload_.size());
Jeff Thompsona92861a2013-10-16 14:06:23 -0700313}
314
315DerByteString::DerByteString(const std::vector<uint8_t>& blob, DerType type)
316 :DerNode(type)
317{
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700318 payload_.insert(payload_.end(), blob.begin(), blob.end());
Jeff Thompsona92861a2013-10-16 14:06:23 -0700319
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700320 DerNode::encodeHeader(payload_.size());
Jeff Thompsona92861a2013-10-16 14:06:23 -0700321}
322
323DerByteString::DerByteString(istream& start)
324 :DerNode(start)
325{}
326
327DerByteString::~DerByteString()
328{}
329
330
331/*
332 * DerBool
333 */
334DerBool::DerBool(bool value)
335 :DerNode(DER_BOOLEAN)
336
337{
338 char payload = (value ? 0xFF : 0x00);
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700339 payload_.push_back(payload);
Jeff Thompsona92861a2013-10-16 14:06:23 -0700340
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700341 DerNode::encodeHeader(payload_.size());
Jeff Thompsona92861a2013-10-16 14:06:23 -0700342}
343
344DerBool::DerBool(istream& start)
345 :DerNode(start)
346{}
347
348DerBool::~DerBool()
349{}
350
351
352/*
353 * DerInteger
354 */
355DerInteger::DerInteger(const vector<uint8_t>& blob)
356 :DerNode(DER_INTEGER)
357{
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700358 payload_.insert(payload_.end(), blob.begin(), blob.end());
Jeff Thompsona92861a2013-10-16 14:06:23 -0700359
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700360 DerNode::encodeHeader(payload_.size());
Jeff Thompsona92861a2013-10-16 14:06:23 -0700361}
362
363DerInteger::DerInteger(istream& start)
364 :DerNode(start)
365{}
366
367DerInteger::~DerInteger()
368{}
369
370
371/*
372 * DerBitString
373 */
374DerBitString::DerBitString(const vector<uint8_t>& blob, uint8_t paddingLen)
375 :DerNode(DER_BIT_STRING)
376{
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700377 payload_.push_back((char)paddingLen);
378 payload_.insert(payload_.end(), blob.begin(), blob.end());
Jeff Thompsona92861a2013-10-16 14:06:23 -0700379
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700380 DerNode::encodeHeader(payload_.size());
Jeff Thompsona92861a2013-10-16 14:06:23 -0700381}
382
383DerBitString::DerBitString(istream& start)
384 :DerNode(start)
385{}
386
387DerBitString::~DerBitString()
388{}
389
390
391/*
392 * DerOctetString
393 */
394DerOctetString::DerOctetString(const string& str)
395 :DerByteString(str, DER_OCTET_STRING)
396{}
397
398DerOctetString::DerOctetString(const vector<uint8_t>& blob)
399 :DerByteString(blob, DER_OCTET_STRING)
400{}
401
402DerOctetString::DerOctetString(istream& start)
403 :DerByteString(start)
404{}
405
406DerOctetString::~DerOctetString()
407{}
408
409
410/*
411 * DerNull
412 */
413DerNull::DerNull()
414 :DerNode(DER_NULL)
415{
416 DerNode::encodeHeader(0);
417}
418
419DerNull::DerNull(istream& start)
420 :DerNode(start)
421{}
422
423DerNull::~DerNull()
424{}
425
426
427/*
428 * DerOid
429 */
430DerOid::DerOid(const OID& oid)
431 :DerNode(DER_OBJECT_IDENTIFIER)
432{
433 prepareEncoding(oid.getIntegerList());
434}
435
436
437DerOid::DerOid(const string& oidStr)
438 :DerNode(DER_OBJECT_IDENTIFIER)
439{
440 vector<int> value;
441
442 string str = oidStr + ".";
443
444 size_t pos = 0;
445 size_t ppos = 0;
446
447 while(string::npos != pos){
448 ppos = pos;
449
450 pos = str.find_first_of('.', pos);
451 if(string::npos == pos)
452 break;
453
454 value.push_back(atoi(str.substr(ppos, pos - ppos).c_str()));
455
456 pos++;
457 }
458
459 prepareEncoding(value);
460}
461
462DerOid::DerOid(const vector<int>& value)
463 :DerNode(DER_OBJECT_IDENTIFIER)
464{
465 prepareEncoding(value);
466}
467
468DerOid::DerOid(istream& start)
469 :DerNode(start)
470{}
471
472DerOid::~DerOid()
473{}
474
475void
476DerOid::prepareEncoding(const vector<int>& value)
477{
478 ostringstream os;
479
480 int firstNumber = 0;
481
482 if(value.size() >= 1){
483 if(0 <= value[0] && 2 >= value[0])
484 firstNumber = value[0] * 40;
485 else
486 throw DerEncodingException("first integer of oid is out of range");
487 }
488 else
489 throw DerEncodingException("no integer in oid");
490
491 if(value.size() >= 2){
492 if(0 <= value[1] && 39 >= value[1])
493 firstNumber += value[1];
494 else
495 throw DerEncodingException("second integer of oid is out of range");
496 }
497
498 encode128(firstNumber, os);
499
500 if(value.size() > 2){
501 int i = 2;
502 for(; i < value.size(); i++)
503 encode128(value[i], os);
504 }
505
506 string output = os.str();
507 DerNode::encodeHeader(output.size());
508
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700509 payload_.insert(payload_.end(), output.begin(), output.end());
Jeff Thompsona92861a2013-10-16 14:06:23 -0700510}
511
512void
513DerOid::encode128(int value, ostringstream& os)
514{
515 int mask = (1 << 7) - 1;
516
517 if(128 > value)
518 {
519 uint8_t singleByte = (uint8_t) mask & value;
520 os.write((char *)&singleByte, 1);
521 }
522 else{
523 uint8_t buf[(sizeof(value)*8 + 6)/7 + 1];
524 uint8_t *p = &(buf[sizeof(buf)-1]);
525 int n = 1;
526
527 p[0] = (uint8_t)(value & mask);
528 value >>= 7;
529
530 while(value != 0)
531 {
532 (--p)[0] = (uint8_t)((value & mask) | (1 << 7));
533 n++;
534 value >>= 7;
535 }
536
537 os.write((char *)p, n);
538 }
539}
540
541int
542DerOid::decode128(int & offset)
543{
544 uint8_t flagMask = 0x80;
545 int result = 0;
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700546 while(payload_[offset] & flagMask){
547 result = 128 * result + (uint8_t) payload_[offset] - 128;
Jeff Thompsona92861a2013-10-16 14:06:23 -0700548 offset++;
549 }
550
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700551 result = result * 128 + payload_[offset];
Jeff Thompsona92861a2013-10-16 14:06:23 -0700552 offset++;
553
554 return result;
555}
556
557
558/*
559 * DerSequence
560 */
561DerSequence::DerSequence()
562 :DerComplex(DER_SEQUENCE)
563{}
564
565DerSequence::DerSequence(istream& start)
566 :DerComplex(start)
567{}
568
569DerSequence::~DerSequence()
570{}
571
572
573/*
574 * DerPrintableString
575 */
576DerPrintableString::DerPrintableString(const string& str)
577 :DerByteString(str, DER_PRINTABLE_STRING)
578{}
579
580DerPrintableString::DerPrintableString(const vector<uint8_t>& blob)
581 :DerByteString(blob, DER_PRINTABLE_STRING)
582{}
583
584DerPrintableString::DerPrintableString(istream& start)
585 :DerByteString(start)
586{}
587
588DerPrintableString::~DerPrintableString()
589{}
590
591
592/*
593 * DerGtime
594 */
595DerGtime::DerGtime(const Time& time)
596 :DerNode(DER_GENERALIZED_TIME)
597{
598 string pTimeStr = toIsoString(time);
599 int index = pTimeStr.find_first_of('T');
600 string derTime = pTimeStr.substr(0, index) + pTimeStr.substr(index+1, pTimeStr.size() - index -1) + "Z";
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700601 payload_.insert(payload_.end(), derTime.begin(), derTime.end());
Jeff Thompsona92861a2013-10-16 14:06:23 -0700602
Jeff Thompson7ff36fe2013-10-16 15:30:13 -0700603 DerNode::encodeHeader(payload_.size());
Jeff Thompsona92861a2013-10-16 14:06:23 -0700604}
605
606DerGtime::DerGtime(istream& start)
607 :DerNode(start)
608{}
609
610DerGtime::~DerGtime()
611{}
612
613string DerGtime::toIsoString(const Time& time)
614{
615#if 1
616 throw std::runtime_error("not implemented");
617#endif
618}
619
620Time DerGtime::fromIsoString(const string& isoString)
621{
622#if 1
623 throw std::runtime_error("not implemented");
624#endif
625}
626
627} // der
628
629}