|
|
// asn.cpp - written and placed in the public domain by Wei Dai
#include "pch.h"
#ifndef CRYPTOPP_IMPORTS
#include "asn.h"
#include <iomanip>
#include <time.h>
NAMESPACE_BEGIN(CryptoPP) USING_NAMESPACE(std)
/// DER Length
size_t DERLengthEncode(BufferedTransformation &bt, lword length) { size_t i=0; if (length <= 0x7f) { bt.Put(byte(length)); i++; } else { bt.Put(byte(BytePrecision(length) | 0x80)); i++; for (int j=BytePrecision(length); j; --j) { bt.Put(byte(length >> (j-1)*8)); i++; } } return i; }
bool BERLengthDecode(BufferedTransformation &bt, lword &length, bool &definiteLength) { byte b;
if (!bt.Get(b)) return false;
if (!(b & 0x80)) { definiteLength = true; length = b; } else { unsigned int lengthBytes = b & 0x7f;
if (lengthBytes == 0) { definiteLength = false; return true; }
definiteLength = true; length = 0; while (lengthBytes--) { if (length >> (8*(sizeof(length)-1))) BERDecodeError(); // length about to overflow
if (!bt.Get(b)) return false;
length = (length << 8) | b; } } return true; }
bool BERLengthDecode(BufferedTransformation &bt, size_t &length) { lword lw; bool definiteLength; if (!BERLengthDecode(bt, lw, definiteLength)) BERDecodeError(); if (!SafeConvert(lw, length)) BERDecodeError(); return definiteLength; }
void DEREncodeNull(BufferedTransformation &out) { out.Put(TAG_NULL); out.Put(0); }
void BERDecodeNull(BufferedTransformation &in) { byte b; if (!in.Get(b) || b != TAG_NULL) BERDecodeError(); size_t length; if (!BERLengthDecode(in, length) || length != 0) BERDecodeError(); }
/// ASN Strings
size_t DEREncodeOctetString(BufferedTransformation &bt, const byte *str, size_t strLen) { bt.Put(OCTET_STRING); size_t lengthBytes = DERLengthEncode(bt, strLen); bt.Put(str, strLen); return 1+lengthBytes+strLen; }
size_t DEREncodeOctetString(BufferedTransformation &bt, const SecByteBlock &str) { return DEREncodeOctetString(bt, str.begin(), str.size()); }
size_t BERDecodeOctetString(BufferedTransformation &bt, SecByteBlock &str) { byte b; if (!bt.Get(b) || b != OCTET_STRING) BERDecodeError();
size_t bc; if (!BERLengthDecode(bt, bc)) BERDecodeError();
str.resize(bc); if (bc != bt.Get(str, bc)) BERDecodeError(); return bc; }
size_t BERDecodeOctetString(BufferedTransformation &bt, BufferedTransformation &str) { byte b; if (!bt.Get(b) || b != OCTET_STRING) BERDecodeError();
size_t bc; if (!BERLengthDecode(bt, bc)) BERDecodeError();
bt.TransferTo(str, bc); return bc; }
size_t DEREncodeTextString(BufferedTransformation &bt, const std::string &str, byte asnTag) { bt.Put(asnTag); size_t lengthBytes = DERLengthEncode(bt, str.size()); bt.Put((const byte *)str.data(), str.size()); return 1+lengthBytes+str.size(); }
size_t BERDecodeTextString(BufferedTransformation &bt, std::string &str, byte asnTag) { byte b; if (!bt.Get(b) || b != asnTag) BERDecodeError();
size_t bc; if (!BERLengthDecode(bt, bc)) BERDecodeError();
SecByteBlock temp(bc); if (bc != bt.Get(temp, bc)) BERDecodeError(); str.assign((char *)temp.begin(), bc); return bc; }
/// ASN BitString
size_t DEREncodeBitString(BufferedTransformation &bt, const byte *str, size_t strLen, unsigned int unusedBits) { bt.Put(BIT_STRING); size_t lengthBytes = DERLengthEncode(bt, strLen+1); bt.Put((byte)unusedBits); bt.Put(str, strLen); return 2+lengthBytes+strLen; }
size_t BERDecodeBitString(BufferedTransformation &bt, SecByteBlock &str, unsigned int &unusedBits) { byte b; if (!bt.Get(b) || b != BIT_STRING) BERDecodeError();
size_t bc; if (!BERLengthDecode(bt, bc)) BERDecodeError();
byte unused; if (!bt.Get(unused)) BERDecodeError(); unusedBits = unused; str.resize(bc-1); if ((bc-1) != bt.Get(str, bc-1)) BERDecodeError(); return bc-1; }
void DERReencode(BufferedTransformation &source, BufferedTransformation &dest) { byte tag; source.Peek(tag); BERGeneralDecoder decoder(source, tag); DERGeneralEncoder encoder(dest, tag); if (decoder.IsDefiniteLength()) decoder.TransferTo(encoder, decoder.RemainingLength()); else { while (!decoder.EndReached()) DERReencode(decoder, encoder); } decoder.MessageEnd(); encoder.MessageEnd(); }
void OID::EncodeValue(BufferedTransformation &bt, word32 v) { for (unsigned int i=RoundUpToMultipleOf(STDMAX(7U,BitPrecision(v)), 7U)-7; i != 0; i-=7) bt.Put((byte)(0x80 | ((v >> i) & 0x7f))); bt.Put((byte)(v & 0x7f)); }
size_t OID::DecodeValue(BufferedTransformation &bt, word32 &v) { byte b; size_t i=0; v = 0; while (true) { if (!bt.Get(b)) BERDecodeError(); i++; if (v >> (8*sizeof(v)-7)) // v about to overflow
BERDecodeError(); v <<= 7; v += b & 0x7f; if (!(b & 0x80)) return i; } }
void OID::DEREncode(BufferedTransformation &bt) const { assert(m_values.size() >= 2); ByteQueue temp; temp.Put(byte(m_values[0] * 40 + m_values[1])); for (size_t i=2; i<m_values.size(); i++) EncodeValue(temp, m_values[i]); bt.Put(OBJECT_IDENTIFIER); DERLengthEncode(bt, temp.CurrentSize()); temp.TransferTo(bt); }
void OID::BERDecode(BufferedTransformation &bt) { byte b; if (!bt.Get(b) || b != OBJECT_IDENTIFIER) BERDecodeError();
size_t length; if (!BERLengthDecode(bt, length) || length < 1) BERDecodeError();
if (!bt.Get(b)) BERDecodeError(); length--; m_values.resize(2); m_values[0] = b / 40; m_values[1] = b % 40;
while (length > 0) { word32 v; size_t valueLen = DecodeValue(bt, v); if (valueLen > length) BERDecodeError(); m_values.push_back(v); length -= valueLen; } }
void OID::BERDecodeAndCheck(BufferedTransformation &bt) const { OID oid(bt); if (*this != oid) BERDecodeError(); }
inline BufferedTransformation & EncodedObjectFilter::CurrentTarget() { if (m_flags & PUT_OBJECTS) return *AttachedTransformation(); else return TheBitBucket(); }
void EncodedObjectFilter::Put(const byte *inString, size_t length) { if (m_nCurrentObject == m_nObjects) { AttachedTransformation()->Put(inString, length); return; }
LazyPutter lazyPutter(m_queue, inString, length);
while (m_queue.AnyRetrievable()) { switch (m_state) { case IDENTIFIER: if (!m_queue.Get(m_id)) return; m_queue.TransferTo(CurrentTarget(), 1); m_state = LENGTH; // fall through
case LENGTH: { byte b; if (m_level > 0 && m_id == 0 && m_queue.Peek(b) && b == 0) { m_queue.TransferTo(CurrentTarget(), 1); m_level--; m_state = IDENTIFIER; break; } ByteQueue::Walker walker(m_queue); bool definiteLength; if (!BERLengthDecode(walker, m_lengthRemaining, definiteLength)) return; m_queue.TransferTo(CurrentTarget(), walker.GetCurrentPosition()); if (!((m_id & CONSTRUCTED) || definiteLength)) BERDecodeError(); if (!definiteLength) { if (!(m_id & CONSTRUCTED)) BERDecodeError(); m_level++; m_state = IDENTIFIER; break; } m_state = BODY; // fall through
} case BODY: m_lengthRemaining -= m_queue.TransferTo(CurrentTarget(), m_lengthRemaining);
if (m_lengthRemaining == 0) m_state = IDENTIFIER; }
if (m_state == IDENTIFIER && m_level == 0) { // just finished processing a level 0 object
++m_nCurrentObject;
if (m_flags & PUT_MESSANGE_END_AFTER_EACH_OBJECT) AttachedTransformation()->MessageEnd();
if (m_nCurrentObject == m_nObjects) { if (m_flags & PUT_MESSANGE_END_AFTER_ALL_OBJECTS) AttachedTransformation()->MessageEnd();
if (m_flags & PUT_MESSANGE_SERIES_END_AFTER_ALL_OBJECTS) AttachedTransformation()->MessageSeriesEnd();
m_queue.TransferAllTo(*AttachedTransformation()); return; } } } }
BERGeneralDecoder::BERGeneralDecoder(BufferedTransformation &inQueue, byte asnTag) : m_inQueue(inQueue), m_finished(false) { Init(asnTag); }
BERGeneralDecoder::BERGeneralDecoder(BERGeneralDecoder &inQueue, byte asnTag) : m_inQueue(inQueue), m_finished(false) { Init(asnTag); }
void BERGeneralDecoder::Init(byte asnTag) { byte b; if (!m_inQueue.Get(b) || b != asnTag) BERDecodeError();
if (!BERLengthDecode(m_inQueue, m_length, m_definiteLength)) BERDecodeError();
if (!m_definiteLength && !(asnTag & CONSTRUCTED)) BERDecodeError(); // cannot be primitive and have indefinite length
}
BERGeneralDecoder::~BERGeneralDecoder() { try // avoid throwing in constructor
{ if (!m_finished) MessageEnd(); } catch (...) { } }
bool BERGeneralDecoder::EndReached() const { if (m_definiteLength) return m_length == 0; else { // check end-of-content octets
word16 i; return (m_inQueue.PeekWord16(i)==2 && i==0); } }
byte BERGeneralDecoder::PeekByte() const { byte b; if (!Peek(b)) BERDecodeError(); return b; }
void BERGeneralDecoder::CheckByte(byte check) { byte b; if (!Get(b) || b != check) BERDecodeError(); }
void BERGeneralDecoder::MessageEnd() { m_finished = true; if (m_definiteLength) { if (m_length != 0) BERDecodeError(); } else { // remove end-of-content octets
word16 i; if (m_inQueue.GetWord16(i) != 2 || i != 0) BERDecodeError(); } }
size_t BERGeneralDecoder::TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel, bool blocking) { if (m_definiteLength && transferBytes > m_length) transferBytes = m_length; size_t blockedBytes = m_inQueue.TransferTo2(target, transferBytes, channel, blocking); ReduceLength(transferBytes); return blockedBytes; }
size_t BERGeneralDecoder::CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end, const std::string &channel, bool blocking) const { if (m_definiteLength) end = STDMIN(m_length, end); return m_inQueue.CopyRangeTo2(target, begin, end, channel, blocking); }
lword BERGeneralDecoder::ReduceLength(lword delta) { if (m_definiteLength) { if (m_length < delta) BERDecodeError(); m_length -= delta; } return delta; }
DERGeneralEncoder::DERGeneralEncoder(BufferedTransformation &outQueue, byte asnTag) : m_outQueue(outQueue), m_finished(false), m_asnTag(asnTag) { }
DERGeneralEncoder::DERGeneralEncoder(DERGeneralEncoder &outQueue, byte asnTag) : m_outQueue(outQueue), m_finished(false), m_asnTag(asnTag) { }
DERGeneralEncoder::~DERGeneralEncoder() { try // avoid throwing in constructor
{ if (!m_finished) MessageEnd(); } catch (...) { } }
void DERGeneralEncoder::MessageEnd() { m_finished = true; lword length = CurrentSize(); m_outQueue.Put(m_asnTag); DERLengthEncode(m_outQueue, length); TransferTo(m_outQueue); }
// *************************************************************
void X509PublicKey::BERDecode(BufferedTransformation &bt) { BERSequenceDecoder subjectPublicKeyInfo(bt); BERSequenceDecoder algorithm(subjectPublicKeyInfo); GetAlgorithmID().BERDecodeAndCheck(algorithm); bool parametersPresent = algorithm.EndReached() ? false : BERDecodeAlgorithmParameters(algorithm); algorithm.MessageEnd();
BERGeneralDecoder subjectPublicKey(subjectPublicKeyInfo, BIT_STRING); subjectPublicKey.CheckByte(0); // unused bits
BERDecodePublicKey(subjectPublicKey, parametersPresent, (size_t)subjectPublicKey.RemainingLength()); subjectPublicKey.MessageEnd(); subjectPublicKeyInfo.MessageEnd(); }
void X509PublicKey::DEREncode(BufferedTransformation &bt) const { DERSequenceEncoder subjectPublicKeyInfo(bt);
DERSequenceEncoder algorithm(subjectPublicKeyInfo); GetAlgorithmID().DEREncode(algorithm); DEREncodeAlgorithmParameters(algorithm); algorithm.MessageEnd();
DERGeneralEncoder subjectPublicKey(subjectPublicKeyInfo, BIT_STRING); subjectPublicKey.Put(0); // unused bits
DEREncodePublicKey(subjectPublicKey); subjectPublicKey.MessageEnd();
subjectPublicKeyInfo.MessageEnd(); }
void PKCS8PrivateKey::BERDecode(BufferedTransformation &bt) { BERSequenceDecoder privateKeyInfo(bt); word32 version; BERDecodeUnsigned<word32>(privateKeyInfo, version, INTEGER, 0, 0); // check version
BERSequenceDecoder algorithm(privateKeyInfo); GetAlgorithmID().BERDecodeAndCheck(algorithm); bool parametersPresent = algorithm.EndReached() ? false : BERDecodeAlgorithmParameters(algorithm); algorithm.MessageEnd();
BERGeneralDecoder octetString(privateKeyInfo, OCTET_STRING); BERDecodePrivateKey(octetString, parametersPresent, (size_t)privateKeyInfo.RemainingLength()); octetString.MessageEnd();
if (!privateKeyInfo.EndReached()) BERDecodeOptionalAttributes(privateKeyInfo); privateKeyInfo.MessageEnd(); }
void PKCS8PrivateKey::DEREncode(BufferedTransformation &bt) const { DERSequenceEncoder privateKeyInfo(bt); DEREncodeUnsigned<word32>(privateKeyInfo, 0); // version
DERSequenceEncoder algorithm(privateKeyInfo); GetAlgorithmID().DEREncode(algorithm); DEREncodeAlgorithmParameters(algorithm); algorithm.MessageEnd();
DERGeneralEncoder octetString(privateKeyInfo, OCTET_STRING); DEREncodePrivateKey(octetString); octetString.MessageEnd();
DEREncodeOptionalAttributes(privateKeyInfo); privateKeyInfo.MessageEnd(); }
void PKCS8PrivateKey::BERDecodeOptionalAttributes(BufferedTransformation &bt) { DERReencode(bt, m_optionalAttributes); }
void PKCS8PrivateKey::DEREncodeOptionalAttributes(BufferedTransformation &bt) const { m_optionalAttributes.CopyTo(bt); }
NAMESPACE_END
#endif
|