/* Copyright (C) Boris Nikolaus, Germany, 1996-1997. All rights reserved. */ /* Copyright (C) Microsoft Corporation, 1997-1998. All rights reserved. */ #include "precomp.h" // THE FOLLOWING IS FROM BERENCOD.C /* get the expected length based on the table */ ASN1uint32_t _BERGetLength(ASN1uint32_t val, const ASN1uint32_t Tbl[], ASN1uint32_t cItems) { ASN1uint32_t i; for (i = 0; i < cItems; i++) { if (val < Tbl[i]) return i+1; } return cItems+1; } static const ASN1uint32_t c_TagTable[] = { 31, 0x80, 0x4000, 0x200000, 0x10000000 }; /* encode a tag */ int ASN1BEREncTag(ASN1encoding_t enc, ASN1uint32_t tag) { ASN1uint32_t tagclass, tagvalue, cbTagLength; tagclass = (tag >> 24) & 0xe0; tagvalue = tag & 0x1fffffff; cbTagLength = _BERGetLength(tagvalue, c_TagTable, ARRAY_SIZE(c_TagTable)); if (ASN1BEREncCheck(enc, cbTagLength)) { if (cbTagLength == 1) { *enc->pos++ = (ASN1octet_t)(tagclass | tagvalue); } else { *enc->pos++ = (ASN1octet_t)(tagclass | 0x1f); switch (cbTagLength) { case 6: *enc->pos++ = (ASN1octet_t)((tagvalue >> 28) | 0x80); // lonchanc: intentionally fall through case 5: *enc->pos++ = (ASN1octet_t)((tagvalue >> 21) | 0x80); // lonchanc: intentionally fall through case 4: *enc->pos++ = (ASN1octet_t)((tagvalue >> 14) | 0x80); // lonchanc: intentionally fall through case 3: *enc->pos++ = (ASN1octet_t)((tagvalue >> 7) | 0x80); // lonchanc: intentionally fall through case 2: *enc->pos++ = (ASN1octet_t)(tagvalue & 0x7f); break; } } return 1; } return 0; } /* put the length value */ void _BERPutLength(ASN1encoding_t enc, ASN1uint32_t len, ASN1uint32_t cbLength) { if (cbLength > 1) { *enc->pos++ = (ASN1octet_t) (0x7f + cbLength); // 0x80 + cbLength - 1; } switch (cbLength) { case 5: *enc->pos++ = (ASN1octet_t)(len >> 24); // lonchanc: intentionally fall through case 4: *enc->pos++ = (ASN1octet_t)(len >> 16); // lonchanc: intentionally fall through case 3: *enc->pos++ = (ASN1octet_t)(len >> 8); // lonchanc: intentionally fall through default: // case 2: case 1: *enc->pos++ = (ASN1octet_t)len; break; } } static const ASN1uint32_t c_LengthTable[] = { 0x80, 0x100, 0x10000, 0x1000000 }; /* encode length */ int ASN1BEREncLength(ASN1encoding_t enc, ASN1uint32_t len) { ASN1uint32_t cbLength = _BERGetLength(len, c_LengthTable, ARRAY_SIZE(c_LengthTable)); if (ASN1BEREncCheck(enc, cbLength + len)) { _BERPutLength(enc, len, cbLength); return 1; } return 0; } /* encode an octet string value */ int ASN1BEREncOctetString(ASN1encoding_t enc, ASN1uint32_t tag, ASN1uint32_t len, ASN1octet_t *val) { /* encode tag */ if (ASN1BEREncTag(enc, tag)) { /* encode length */ if (ASN1BEREncLength(enc, len)) { /* copy value */ CopyMemory(enc->pos, val, len); enc->pos += len; return 1; } } return 0; } /* encode a boolean value */ int ASN1BEREncBool(ASN1encoding_t enc, ASN1uint32_t tag, ASN1bool_t val) { if (ASN1BEREncTag(enc, tag)) { if (ASN1BEREncLength(enc, 1)) { *enc->pos++ = val ? 0xFF : 0; return 1; } } return 0; } static const c_U32LengthTable[] = { 0x80, 0x8000, 0x800000, 0x80000000 }; /* encode a unsigned integer value */ int ASN1BEREncU32(ASN1encoding_t enc, ASN1uint32_t tag, ASN1uint32_t val) { EncAssert(enc, tag != 0x01); if (ASN1BEREncTag(enc, tag)) { ASN1uint32_t cbLength; cbLength = _BERGetLength(val, c_U32LengthTable, ARRAY_SIZE(c_U32LengthTable)); if (ASN1BEREncLength(enc, cbLength)) { switch (cbLength) { case 5: *enc->pos++ = 0; // lonchanc: intentionally fall through case 4: *enc->pos++ = (ASN1octet_t)(val >> 24); // lonchanc: intentionally fall through case 3: *enc->pos++ = (ASN1octet_t)(val >> 16); // lonchanc: intentionally fall through case 2: *enc->pos++ = (ASN1octet_t)(val >> 8); // lonchanc: intentionally fall through case 1: *enc->pos++ = (ASN1octet_t)(val); break; } return 1; } } return 0; } // THE FOLLOWING IS FROM BERDECOD.C /* check if len octets are left in decoding stream */ int ASN1BERDecCheck(ASN1decoding_t dec, ASN1uint32_t len) { if (dec->pos + len <= dec->buf + dec->size) { return 1; } ASN1DecSetError(dec, ASN1_ERR_EOD); return 0; } int _BERDecPeekCheck(ASN1decoding_t dec, ASN1uint32_t len) { return ((dec->pos + len <= dec->buf + dec->size) ? 1 : 0); } /* start decoding of a constructed value */ int _BERDecConstructed(ASN1decoding_t dec, ASN1uint32_t len, ASN1uint32_t infinite, ASN1decoding_t *dd, ASN1octet_t **ppBufEnd) { // safety net DecAssert(dec, NULL != dd); *dd = dec; #if 0 // NO_NESTED_DECODING // lonchanc: this does not work because open type can be the last component and // the open type decoder needs to peek a tag. as a result, we may peek the tag // outside the buffer boundary. if (ppBufEnd && (! infinite)) { *ppBufEnd = dec->pos + len; return 1; } #endif /* initialize a new decoding stream as child of running decoding stream */ if (ASN1_CreateDecoder(dec->module, dd, dec->pos, infinite ? dec->size - (ASN1uint32_t) (dec->pos - dec->buf) : len, dec) >= 0) { /* set pointer to end of decoding stream if definite length case selected */ *ppBufEnd = infinite ? NULL : (*dd)->buf + (*dd)->size; return 1; } return 0; } /* decode a tag value; return constructed bit if desired */ int ASN1BERDecTag(ASN1decoding_t dec, ASN1uint32_t tag, ASN1uint32_t *constructed) { ASN1uint32_t tagvalue, tagclass, c; /* get tag class and value */ if (ASN1BERDecCheck(dec, 1)) { tagclass = *dec->pos & 0xe0; tagvalue = *dec->pos++ & 0x1f; if (tagvalue == 0x1f) { tagvalue = 0; do { if (ASN1BERDecCheck(dec, 1)) { c = *dec->pos++; if (! (tagvalue & 0xe0000000)) { tagvalue = (tagvalue << 7) | (c & 0x7f); } else { ASN1DecSetError(dec, ASN1_ERR_BADTAG); return 0; } } else { return 0; } } while (c & 0x80); } /* extract constructed bit if wanted */ if (constructed) { *constructed = tagclass & 0x20; tagclass &= ~0x20; } /* check if tag equals desires */ if (tag == ((tagclass << 24) | tagvalue)) { return 1; } ASN1DecSetError(dec, ASN1_ERR_BADTAG); } return 0; } /* decode length */ int ASN1BERDecLength(ASN1decoding_t dec, ASN1uint32_t *len, ASN1uint32_t *infinite) { // default is definite length if (infinite) { *infinite = 0; } /* get length and infinite flag */ if (ASN1BERDecCheck(dec, 1)) { ASN1uint32_t l = *dec->pos++; if (l < 0x80) { *len = l; } else if (l == 0x80) { *len = 0; if (infinite) { *infinite = 1; } else { ASN1DecSetError(dec, ASN1_ERR_CORRUPT); return 0; } } else if (l <= 0x84) { ASN1uint32_t i = l - 0x80; if (ASN1BERDecCheck(dec, i)) { l = 0; switch (i) { case 4: l = *dec->pos++ << 24; /*FALLTHROUGH*/ case 3: l |= *dec->pos++ << 16; /*FALLTHROUGH*/ case 2: l |= *dec->pos++ << 8; /*FALLTHROUGH*/ case 1: l |= *dec->pos++; break; } *len = l; } else { return 0; } } else { ASN1DecSetError(dec, ASN1_ERR_CORRUPT); return 0; } /* check if enough octets left if length is known */ if (!infinite || !*infinite) { return ASN1BERDecCheck(dec, *len); } return 1; } return 0; } /* decode an explicit tag */ int ASN1BERDecExplicitTag(ASN1decoding_t dec, ASN1uint32_t tag, ASN1decoding_t *dd, ASN1octet_t **ppBufEnd) { ASN1uint32_t len, infinite, constructed; // safety net if (dd) { *dd = dec; } /* skip the constructed tag */ if (ASN1BERDecTag(dec, tag | 0x20000000, NULL)) { /* get the length */ if (ASN1BERDecLength(dec, &len, &infinite)) { /* start decoding of constructed value */ if (! dd) { *ppBufEnd = infinite ? NULL : dec->pos + len; return 1; } return _BERDecConstructed(dec, len, infinite, dd, ppBufEnd); } } return 0; } /* decode octet string value */ int _BERDecOctetString(ASN1decoding_t dec, ASN1uint32_t tag, ASN1octetstring_t *val, ASN1uint32_t fNoCopy) { ASN1INTERNdecoding_t d = (ASN1INTERNdecoding_t)dec; ASN1uint32_t constructed, len, infinite; ASN1decoding_t dd; ASN1octet_t *di; if (ASN1BERDecTag(dec, tag, &constructed)) { if (ASN1BERDecLength(dec, &len, &infinite)) { if (! constructed) { val->length = len; if (fNoCopy) { val->value = dec->pos; dec->pos += len; return 1; } else { if (len) { val->value = (ASN1octet_t *)DecMemAlloc(dec, len); if (val->value) { CopyMemory(val->value, dec->pos, len); dec->pos += len; return 1; } } else { val->value = NULL; return 1; } } } else { ASN1octetstring_t o; val->length = 0; val->value = NULL; if (_BERDecConstructed(dec, len, infinite, &dd, &di)) { while (ASN1BERDecNotEndOfContents(dd, di)) { o.length = 0; o.value = NULL; if (_BERDecOctetString(dd, 0x4, &o, fNoCopy)) { if (o.length) { if (fNoCopy) { *val = o; break; // break out the loop because nocopy cannot have multiple constructed streams } /* resize value */ val->value = (ASN1octet_t *)DecMemReAlloc(dd, val->value, val->length + o.length); if (val->value) { /* concat octet strings */ CopyMemory(val->value + val->length, o.value, o.length); val->length += o.length; /* free unused octet string */ DecMemFree(dec, o.value); } else { return 0; } } } } return ASN1BERDecEndOfContents(dec, dd, di); } } } } return 0; } /* decode octet string value, making copy */ int ASN1BERDecOctetString(ASN1decoding_t dec, ASN1uint32_t tag, ASN1octetstring_t *val) { return _BERDecOctetString(dec, tag, val, FALSE); } /* decode octet string value, no copy */ int ASN1BERDecOctetString2(ASN1decoding_t dec, ASN1uint32_t tag, ASN1octetstring_t *val) { return _BERDecOctetString(dec, tag, val, TRUE); } /* peek the following tag without advancing the read position */ int ASN1BERDecPeekTag(ASN1decoding_t dec, ASN1uint32_t *tag) { ASN1uint32_t tagvalue, tagclass, c; ASN1octet_t *p; *tag = 0; // invalid tag if (_BERDecPeekCheck(dec, 1)) { p = dec->pos; /* get tagclass without primitive/constructed bit */ tagclass = *dec->pos & 0xc0; /* get tag value */ tagvalue = *dec->pos++ & 0x1f; if (tagvalue == 0x1f) { tagvalue = 0; do { if (_BERDecPeekCheck(dec, 1)) { c = *dec->pos++; if (! (tagvalue & 0xe0000000)) { tagvalue = (tagvalue << 7) | (c & 0x7f); } else { ASN1DecSetError(dec, ASN1_ERR_BADTAG); return 0; } } else { return 0; } } while (c & 0x80); } /* return tag */ *tag = ((tagclass << 24) | tagvalue); /* reset decoding position */ dec->pos = p; return 1; } return 0; } /* decode boolean into ASN1boot_t */ int ASN1BERDecBool(ASN1decoding_t dec, ASN1uint32_t tag, ASN1bool_t *val) { /* skip tag */ if (ASN1BERDecTag(dec, tag, NULL)) { /* get length */ ASN1uint32_t len; if (ASN1BERDecLength(dec, &len, NULL)) { if (len >= 1) { DecAssert(dec, len == 1); *val = *dec->pos ? 1 : 0; dec->pos += len; // self defensive return 1; } } } return 0; } /* decode integer into unsigned 32 bit value */ int ASN1BERDecU32Val(ASN1decoding_t dec, ASN1uint32_t tag, ASN1uint32_t *val) { ASN1uint32_t len; /* skip tag */ if (ASN1BERDecTag(dec, tag, NULL)) { /* get length */ if (ASN1BERDecLength(dec, &len, NULL)) { /* get value */ if (len >= 1) { switch (len) { case 1: *val = *dec->pos++; break; case 2: *val = (*dec->pos << 8) | dec->pos[1]; dec->pos += 2; break; case 3: *val = (*dec->pos << 16) | (dec->pos[1] << 8) | dec->pos[2]; dec->pos += 3; break; case 4: *val = (*dec->pos << 24) | (dec->pos[1] << 16) | (dec->pos[2] << 8) | dec->pos[3]; dec->pos += 4; break; case 5: if (! *dec->pos) { *val = (dec->pos[1] << 24) | (dec->pos[2] << 16) | (dec->pos[3] << 8) | dec->pos[4]; dec->pos += 5; break; } // intentionally fall through default: ASN1DecSetError(dec, ASN1_ERR_LARGE); return 0; } return 1; } else { ASN1DecSetError(dec, ASN1_ERR_CORRUPT); return 0; } } } return 0; } int ASN1BERDecEndOfContents(ASN1decoding_t dec, ASN1decoding_t dd, ASN1octet_t *pBufEnd) { ASN1error_e err = ASN1_ERR_CORRUPT; if (! dd) { dd = dec; } DecAssert(dec, NULL != dd); if (pBufEnd) { /* end of definite length case: */ /* check if decoded up to end of contents */ if (dd->pos == pBufEnd) { dec->pos = pBufEnd; err = ASN1_SUCCESS; } } else { /* end of infinite length case: */ /* expect end-of-contents octets */ if (ASN1BERDecCheck(dd, 2)) { if (0 == dd->pos[0] && 0 == dd->pos[1]) { dd->pos += 2; if (dd != dec) { /* finit child decoding stream and update parent decoding stream */ dec->pos = dd->pos; } err = ASN1_SUCCESS; } } else { err = ASN1_ERR_EOD; } } if (dd && dd != dec) { ASN1_CloseDecoder(dd); } if (ASN1_SUCCESS == err) { return 1; } ASN1DecSetError(dec, err); return 0; } /* check if end of contents (of a constructed value) has been reached */ int ASN1BERDecNotEndOfContents(ASN1decoding_t dec, ASN1octet_t *pBufEnd) { return (pBufEnd ? (dec->pos < pBufEnd) : (ASN1BERDecCheck(dec, 2) && (dec->pos[0] || dec->pos[1]))); } #ifdef ENABLE_BER typedef struct { ASN1octet_t *pBuf; ASN1uint32_t cbBufSize; } CER_BLK_BUF; typedef struct { ASN1blocktype_e eBlkType; ASN1encoding_t encPrimary; ASN1encoding_t encSecondary; ASN1uint32_t nMaxBlkSize; ASN1uint32_t nCurrBlkSize; CER_BLK_BUF *aBlkBuf; } CER_BLOCK; #define MAX_INIT_BLK_SIZE 16 int ASN1CEREncBeginBlk(ASN1encoding_t enc, ASN1blocktype_e eBlkType, void **ppBlk_) { CER_BLOCK *pBlk = (CER_BLOCK *) EncMemAlloc(enc, sizeof(CER_BLOCK)); if (NULL != pBlk) { EncAssert(enc, ASN1_DER_SET_OF_BLOCK == eBlkType); pBlk->eBlkType = eBlkType; pBlk->encPrimary = enc; pBlk->encSecondary = NULL; pBlk->nMaxBlkSize = MAX_INIT_BLK_SIZE; pBlk->nCurrBlkSize = 0; pBlk->aBlkBuf = (CER_BLK_BUF *)EncMemAlloc(enc, MAX_INIT_BLK_SIZE * sizeof(CER_BLK_BUF)); if (NULL != pBlk->aBlkBuf) { *ppBlk_ = (void *) pBlk; return 1; } EncMemFree(enc, pBlk); } return 0; } int ASN1CEREncNewBlkElement(void *pBlk_, ASN1encoding_t *enc2) { CER_BLOCK *pBlk = (CER_BLOCK *) pBlk_; if (NULL == pBlk->encSecondary) { if (ASN1_SUCCESS == ASN1_CreateEncoder(pBlk->encPrimary->module, &(pBlk->encSecondary), NULL, 0, pBlk->encPrimary)) { pBlk->encSecondary->eRule = pBlk->encPrimary->eRule; *enc2 = pBlk->encSecondary; return 1; } } else { ASN1INTERNencoding_t e = (ASN1INTERNencoding_t) (*enc2 = pBlk->encSecondary); ZeroMemory(e, sizeof(*e)); e->info.magic = MAGIC_ENCODER; // e->info.err = ASN1_SUCCESS; // e->info.pos = e->info.buf = NULL; // e->info.size = e->info.len = e->info.bit = 0; // e->info.dwFlags = 0; e->info.module = pBlk->encPrimary->module; e->info.eRule = pBlk->encPrimary->eRule; ((ASN1INTERNencoding_t) pBlk->encPrimary)->child = e; e->parent = (ASN1INTERNencoding_t) pBlk->encPrimary; // e->child = NULL; // e->mem = NULL; // e->memlength = 0; // e->memsize = 0; // e->epi = NULL; // e->epilength = 0; // e->episize = 0; // e->csi = NULL; // e->csilength = 0; // e->csisize = 0; if (ASN1BEREncCheck((ASN1encoding_t) e, 1)) { // lonchanc: make sure the first byte is zeroed out, which // is required for h245. e->info.buf[0] = '\0'; return 1; } } *enc2 = NULL; return 0; } int ASN1CEREncFlushBlkElement(void *pBlk_) { CER_BLOCK *pBlk = (CER_BLOCK *) pBlk_; ASN1encoding_t enc = pBlk->encSecondary; ASN1uint32_t i; if (ASN1BEREncFlush(enc)) { // make sure we have enough space... if (pBlk->nCurrBlkSize >= pBlk->nMaxBlkSize) { CER_BLK_BUF *aBlkBuf = (CER_BLK_BUF *)EncMemAlloc(pBlk->encPrimary, (pBlk->nMaxBlkSize << 1) * sizeof(CER_BLK_BUF)); if (NULL != aBlkBuf) { CopyMemory(aBlkBuf, pBlk->aBlkBuf, pBlk->nMaxBlkSize * sizeof(CER_BLK_BUF)); EncMemFree(pBlk->encPrimary, pBlk->aBlkBuf); pBlk->aBlkBuf = aBlkBuf; pBlk->nMaxBlkSize <<= 1; } else { return 0; } } if (pBlk->encPrimary->eRule & (ASN1_BER_RULE_DER | ASN1_BER_RULE_CER)) { // we need to sort these octet strings for (i = 0; i < pBlk->nCurrBlkSize; i++) { if (0 >= My_memcmp(enc->buf, enc->len, pBlk->aBlkBuf[i].pBuf, pBlk->aBlkBuf[i].cbBufSize)) { ASN1uint32_t cnt = pBlk->nCurrBlkSize - i; ASN1uint32_t j; for (j = pBlk->nCurrBlkSize; cnt--; j--) { pBlk->aBlkBuf[j] = pBlk->aBlkBuf[j-1]; } // i is the place to hold the new one break; } } } else { EncAssert(enc, ASN1_BER_RULE_BER == pBlk->encPrimary->eRule); i = pBlk->nCurrBlkSize; } // remeber the new one. pBlk->aBlkBuf[i].pBuf = enc->buf; pBlk->aBlkBuf[i].cbBufSize = enc->len; pBlk->nCurrBlkSize++; // clean up the encoder structure enc->buf = enc->pos = NULL; enc->size = enc->len = 0; return 1; } return 0; } int ASN1CEREncEndBlk(void *pBlk_) { CER_BLOCK *pBlk = (CER_BLOCK *) pBlk_; ASN1encoding_t enc = pBlk->encPrimary; ASN1uint32_t cbTotalSize = 0; ASN1uint32_t i; int fRet = 0; // calculate the total size for all the buffers. for (i = 0; i < pBlk->nCurrBlkSize; i++) { cbTotalSize += pBlk->aBlkBuf[i].cbBufSize; } if (ASN1BEREncCheck(enc, cbTotalSize)) { for (i = 0; i < pBlk->nCurrBlkSize; i++) { ASN1uint32_t cbBufSize = pBlk->aBlkBuf[i].cbBufSize; CopyMemory(enc->pos, pBlk->aBlkBuf[i].pBuf, cbBufSize); enc->pos += cbBufSize; } fRet = 1; } // free these block buffers. for (i = 0; i < pBlk->nCurrBlkSize; i++) { EncMemFree(enc, pBlk->aBlkBuf[i].pBuf); } // free the block buffer array EncMemFree(enc, pBlk->aBlkBuf); // free the secondary encoder structure ASN1_CloseEncoder(pBlk->encSecondary); // free the block structure itself. EncMemFree(enc, pBlk); return fRet; } #endif // ENABLE_BER /* encode explicit tag */ int ASN1BEREncExplicitTag(ASN1encoding_t enc, ASN1uint32_t tag, ASN1uint32_t *pnLenOff) { /* encode tag */ if (ASN1BEREncTag(enc, tag | 0x20000000)) { /* encode infinite length */ if (ASN1BEREncCheck(enc, 1)) { if (ASN1_BER_RULE_CER != enc->eRule) { // BER and DER always use definite length form. /* return the place to hold the length */ *pnLenOff = (ASN1uint32_t) (enc->pos++ - enc->buf); } else { // CER sub-rule always use indefinite length form. *enc->pos++ = 0x80; *pnLenOff = 0; } return 1; } } return 0; } /* encode definite length */ int ASN1BEREncEndOfContents(ASN1encoding_t enc, ASN1uint32_t nLenOff) { if (ASN1_BER_RULE_CER != enc->eRule) { ASN1octet_t *pbLen = enc->buf + nLenOff; ASN1uint32_t len = (ASN1uint32_t) (enc->pos - pbLen - 1); ASN1uint32_t cbLength = _BERGetLength(len, c_LengthTable, ARRAY_SIZE(c_LengthTable)); ASN1uint32_t i; if (cbLength == 1) { *pbLen = (ASN1octet_t) len; return 1; } // we have to move the octets upward by cbLength-1 // --cbLength; if (ASN1BEREncCheck(enc, cbLength-1)) { // update pbLen because enc->buf may change due to realloc. pbLen = enc->buf + nLenOff; // move memory MoveMemory(pbLen + cbLength, pbLen + 1, len); // put the length enc->pos = pbLen; _BERPutLength(enc, len, cbLength); EncAssert(enc, enc->pos == pbLen + cbLength); // set up new position pointer. // now enc->pos is at the beginning of contents. enc->pos += len; return 1; } } else { EncAssert(enc, 0 == nLenOff); if (ASN1BEREncCheck(enc, 2)) { *enc->pos++ = 0; *enc->pos++ = 0; return 1; } } return 0; } // The following is for CryptoAPI #ifdef ENABLE_BER #include // max num of octets, ceiling of 64 / 7, is 10 #define MAX_BYTES_PER_NODE 10 ASN1uint32_t _BEREncOidNode64(ASN1encoding_t enc, unsigned __int64 n64, ASN1octet_t *pOut) { ASN1uint32_t Low32, i, cb; ASN1octet_t aLittleEndian[MAX_BYTES_PER_NODE]; ZeroMemory(aLittleEndian, sizeof(aLittleEndian)); for (i = 0; n64 != 0; i++) { Low32 = *(ASN1uint32_t *) &n64; aLittleEndian[i] = (ASN1octet_t) (Low32 & 0x7f); n64 = Int64ShrlMod32(n64, 7); } cb = i ? i : 1; // at least one byte for zero value EncAssert(enc, cb <= MAX_BYTES_PER_NODE); for (i = 0; i < cb; i++) { EncAssert(enc, 0 == (0x80 & aLittleEndian[cb - i - 1])); *pOut++ = (ASN1octet_t) (0x80 | aLittleEndian[cb - i - 1]); } *(pOut-1) &= 0x7f; return cb; } int ASN1BERDotVal2Eoid(ASN1encoding_t enc, char *pszDotVal, ASN1encodedOID_t *pOut) { ASN1uint32_t cNodes, cbMaxSize, cb1, cb2; char *psz; // calculate how many nodes, at least 1. for (cNodes = 0, psz = pszDotVal; NULL != psz; cNodes++) { psz = strchr(psz, '.'); if (psz) { psz++; } } // calculate how many bytes should be allocated cb1 = My_lstrlenA(pszDotVal); cb2 = cNodes * MAX_BYTES_PER_NODE; cbMaxSize = (cb1 > cb2) ? cb1 : cb2; // allocate buffer pOut->length = 0; // safety net pOut->value = (ASN1octet_t *) EncMemAlloc(enc, cbMaxSize); if (pOut->value) { ASN1octet_t *p = pOut->value; ASN1uint32_t i; unsigned __int64 n64; psz = pszDotVal; for (i = 0; i < cNodes; i++) { EncAssert(enc, NULL != psz); n64 = (unsigned __int64) _atoi64(psz); psz = strchr(psz, '.') + 1; if (0 == i && cNodes > 1) { i++; n64 = n64 * 40 + (unsigned __int64) _atoi64(psz); psz = strchr(psz, '.') + 1; } p += _BEREncOidNode64(enc, n64, p); } pOut->length = (ASN1uint16_t) (p - pOut->value); EncAssert(enc, pOut->length <= cbMaxSize); return 1; } pOut->length = 0; return 0; } ASN1uint32_t _BERDecOidNode64(unsigned __int64 *pn64, ASN1octet_t *pIn) { ASN1uint32_t c; *pn64 = 0; for (c = 1; TRUE; c++) { *pn64 = Int64ShllMod32(*pn64, 7) + (unsigned __int64) (*pIn & 0x7f); if (!(*pIn++ & 0x80)) { return c; } } return 0; } int ASN1BEREoid2DotVal(ASN1decoding_t dec, ASN1encodedOID_t *pIn, char **ppszDotVal) { ASN1octet_t *p; ASN1uint32_t i, cNodes, cb, n32; unsigned __int64 n64; char *psz; char szBuf[256]; // should be large enough // null out return value *ppszDotVal = NULL; if (NULL == dec) { return 0; } // calculate how many nodes cNodes = 0; for (p = pIn->value, i = 0; i < pIn->length; p++, i++) { if (!(*p & 0x80)) { cNodes++; } } if (cNodes++) // first encoded node consists of two nodes { // decode nodes one by one psz = &szBuf[0]; p = pIn->value; for (i = 0; i < cNodes; i++) { p += _BERDecOidNode64(&n64, p); if (!i) { // first node n32 = (ASN1uint32_t) (n64 / 40); if (n32 > 2) { n32 = 2; } n64 -= (unsigned __int64) (40 * n32); i++; // first encoded node actually consists of two nodes _ultoa(n32, psz, 10); psz += lstrlenA(psz); *psz++ = '.'; } _ui64toa(n64, psz, 10); psz += lstrlenA(psz); *psz++ = '.'; } DecAssert(dec, psz > &szBuf[0]); *(psz-1) = '\0'; // duplicate the string cb = (ASN1uint32_t) (psz - &szBuf[0]); *ppszDotVal = (char *) DecMemAlloc(dec, cb); if (*ppszDotVal) { CopyMemory(*ppszDotVal, &szBuf[0], cb); return 1; } } return 0; } /* encode an object identifier value */ int ASN1BEREncEoid(ASN1encoding_t enc, ASN1uint32_t tag, ASN1encodedOID_t *val) { /* encode tag */ if (ASN1BEREncTag(enc, tag)) { /* encode length */ int rc = ASN1BEREncLength(enc, val->length); if (rc) { /* copy value */ CopyMemory(enc->pos, val->value, val->length); enc->pos += val->length; } return rc; } return 0; } /* decode object identifier value */ int ASN1BERDecEoid(ASN1decoding_t dec, ASN1uint32_t tag, ASN1encodedOID_t *val) { val->length = 0; // safety net if (ASN1BERDecTag(dec, tag, NULL)) { ASN1uint32_t len; if (ASN1BERDecLength(dec, &len, NULL)) { val->length = (ASN1uint16_t) len; if (len) { val->value = (ASN1octet_t *) DecMemAlloc(dec, len); if (val->value) { CopyMemory(val->value, dec->pos, len); dec->pos += len; return 1; } } else { val->value = NULL; return 1; } } } return 0; } void ASN1BEREoid_free(ASN1encodedOID_t *val) { if (val) { MemFree(val->value); } } #endif // ENABLE_BER