diff --git a/ASN1PayloadStructure b/ASN1PayloadStructure new file mode 100644 index 0000000..87b23ae --- /dev/null +++ b/ASN1PayloadStructure @@ -0,0 +1,13 @@ +ReceiptModule DEFINITIONS ::= +BEGIN + +ReceiptAttribute ::= SEQUENCE { + type INTEGER, + version INTEGER, + value OCTET STRING +} + +Payload ::= SET OF ReceiptAttribute + +END + diff --git a/Example/main.swift b/Example/main.swift new file mode 100644 index 0000000..0125e80 --- /dev/null +++ b/Example/main.swift @@ -0,0 +1,38 @@ +// +// main.swift +// Example +// +// Created by Pavel Tikhonenko on 23/06/2019. +// Copyright © 2019 Pavel Tikhonenko. All rights reserved. +// + +import Foundation +import TPInAppReceipt + +print("Hello, World!") + +func testNoOpenssl() +{ + //self.measure + //{ + let mock = try! PKCS7WrapperMock() + mock.extractASN1Data().enumerateASN1AttributesNoOpenssl(withBlock: { (item) in + + }) + + //} +} + +func test() +{ + // self.measure + // { + let mock = try! PKCS7WrapperMock() + mock.extractASN1Data().enumerateASN1Attributes(withBlock: { (item) in + + }) + + // } +} + +testNoOpenssl() diff --git a/TPInAppReceipt.xcodeproj/project.pbxproj b/TPInAppReceipt.xcodeproj/project.pbxproj index a34f4d9..5da84e4 100644 --- a/TPInAppReceipt.xcodeproj/project.pbxproj +++ b/TPInAppReceipt.xcodeproj/project.pbxproj @@ -91,6 +91,7 @@ 47209AC31D9E111C0010BCDE /* InAppReceiptManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47209ABF1D9E111C0010BCDE /* InAppReceiptManager.swift */; }; 47209AC51D9E112C0010BCDE /* AppleIncRootCertificate.cer in Resources */ = {isa = PBXBuildFile; fileRef = 47209AC41D9E112C0010BCDE /* AppleIncRootCertificate.cer */; }; 47209AC61D9E112C0010BCDE /* AppleIncRootCertificate.cer in Resources */ = {isa = PBXBuildFile; fileRef = 47209AC41D9E112C0010BCDE /* AppleIncRootCertificate.cer */; }; + 4728B65922BE3DB900607E5E /* Asn1Coder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4728B65822BE3DB900607E5E /* Asn1Coder.swift */; }; 47589AE51E319A220047DFCD /* Validation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47589AE41E319A220047DFCD /* Validation.swift */; }; 47589AE71E31AE6F0047DFCD /* PKCS7Wrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47589AE61E31AE6F0047DFCD /* PKCS7Wrapper.swift */; }; 47589AE91E31B2F90047DFCD /* InAppPurchase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47589AE81E31B2F90047DFCD /* InAppPurchase.swift */; }; @@ -100,7 +101,6 @@ 47589AF41E333F450047DFCD /* IARError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47589AEE1E332D5D0047DFCD /* IARError.swift */; }; 47589AF51E333F450047DFCD /* Date+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 479DC54C1DA0B8BB00D9A5E3 /* Date+Extension.swift */; }; 47589AF61E333F450047DFCD /* InAppPurchase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47589AE81E31B2F90047DFCD /* InAppPurchase.swift */; }; - 47589AF81E333F450047DFCD /* ASN1Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47209ABC1D9E111C0010BCDE /* ASN1Helper.swift */; }; 47589AF91E333F450047DFCD /* Data+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47209ABD1D9E111C0010BCDE /* Data+Extension.swift */; }; 47589AFA1E333F450047DFCD /* InAppReceipt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47209ABE1D9E111C0010BCDE /* InAppReceipt.swift */; }; 47589AFB1E333F450047DFCD /* Validation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47589AE41E319A220047DFCD /* Validation.swift */; }; @@ -185,9 +185,22 @@ 47589B4F1E333F450047DFCD /* AppleIncRootCertificate.cer in Resources */ = {isa = PBXBuildFile; fileRef = 47209AC41D9E112C0010BCDE /* AppleIncRootCertificate.cer */; }; 47589B561E3342490047DFCD /* DeviceGUIDRetriever.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47589B551E3342490047DFCD /* DeviceGUIDRetriever.swift */; }; 47589B571E3342490047DFCD /* DeviceGUIDRetriever.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47589B551E3342490047DFCD /* DeviceGUIDRetriever.swift */; }; + 476C64BE22BE6DC100D973F9 /* PCKS7.swift in Sources */ = {isa = PBXBuildFile; fileRef = 476C64BD22BE6DC100D973F9 /* PCKS7.swift */; }; + 476C64C622BFC76000D973F9 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 476C64C522BFC76000D973F9 /* main.swift */; }; + 476C64CA22BFC93E00D973F9 /* PCKS7.swift in Sources */ = {isa = PBXBuildFile; fileRef = 476C64BD22BE6DC100D973F9 /* PCKS7.swift */; }; + 476C64CB22BFC94400D973F9 /* Asn1Coder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4728B65822BE3DB900607E5E /* Asn1Coder.swift */; }; + 476C64CC22BFC94400D973F9 /* ASN1Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47209ABC1D9E111C0010BCDE /* ASN1Helper.swift */; }; + 476C64CD22BFC9AA00D973F9 /* TPInAppReceipt.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 47589B531E333F450047DFCD /* TPInAppReceipt.framework */; }; + 476C64CE22BFCCB400D973F9 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 470D079C203B4FC700F3335F /* Security.framework */; }; + 476C64CF22BFCCD500D973F9 /* libcrypto.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 47D2132E1E4588CF00994B00 /* libcrypto.a */; }; + 476C64D022BFCCD500D973F9 /* libssl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 47D2132F1E4588CF00994B00 /* libssl.a */; }; + 476C64D122BFCCDE00D973F9 /* libcrypto.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 47D2132E1E4588CF00994B00 /* libcrypto.a */; }; + 476C64D222BFCCDE00D973F9 /* libssl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 47D2132F1E4588CF00994B00 /* libssl.a */; }; + 476C64D422C028D300D973F9 /* ASN1Object.swift in Sources */ = {isa = PBXBuildFile; fileRef = 476C64D322C028D300D973F9 /* ASN1Object.swift */; }; + 476C64D622C028F800D973F9 /* ASN1Object+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 476C64D522C028F800D973F9 /* ASN1Object+Helper.swift */; }; + 476C64D822C0298000D973F9 /* ASN1Object+ValueReading.swift in Sources */ = {isa = PBXBuildFile; fileRef = 476C64D722C0298000D973F9 /* ASN1Object+ValueReading.swift */; }; + 476C64DA22C0330500D973F9 /* ASN1Object+Sequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 476C64D922C0330500D973F9 /* ASN1Object+Sequence.swift */; }; 479DC54D1DA0B8BB00D9A5E3 /* Date+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 479DC54C1DA0B8BB00D9A5E3 /* Date+Extension.swift */; }; - 47D213301E4588CF00994B00 /* libcrypto.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 47D2132E1E4588CF00994B00 /* libcrypto.a */; }; - 47D213311E4588CF00994B00 /* libssl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 47D2132F1E4588CF00994B00 /* libssl.a */; }; 47D213341E4588D800994B00 /* libcrypto.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 47D213321E4588D800994B00 /* libcrypto.a */; }; 47D213351E4588D800994B00 /* libssl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 47D213331E4588D800994B00 /* libssl.a */; }; 47D2133A1E4738AB00994B00 /* Initialization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47D213391E4738AB00994B00 /* Initialization.swift */; }; @@ -205,6 +218,18 @@ }; /* End PBXContainerItemProxy section */ +/* Begin PBXCopyFilesBuildPhase section */ + 476C64C122BFC76000D973F9 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + /* Begin PBXFileReference section */ 10738491DC109D48ABBBDEAE /* InAppReceiptTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InAppReceiptTests.swift; sourceTree = ""; }; 470D079C203B4FC700F3335F /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; @@ -295,6 +320,7 @@ 47209ABF1D9E111C0010BCDE /* InAppReceiptManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InAppReceiptManager.swift; sourceTree = ""; }; 47209AC41D9E112C0010BCDE /* AppleIncRootCertificate.cer */ = {isa = PBXFileReference; lastKnownFileType = file; path = AppleIncRootCertificate.cer; sourceTree = ""; }; 47209ACD1D9E92CC0010BCDE /* TPInAppReceipt.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; path = TPInAppReceipt.podspec; sourceTree = ""; }; + 4728B65822BE3DB900607E5E /* Asn1Coder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Asn1Coder.swift; sourceTree = ""; }; 47589AE41E319A220047DFCD /* Validation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Validation.swift; sourceTree = ""; }; 47589AE61E31AE6F0047DFCD /* PKCS7Wrapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PKCS7Wrapper.swift; sourceTree = ""; }; 47589AE81E31B2F90047DFCD /* InAppPurchase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InAppPurchase.swift; sourceTree = ""; }; @@ -302,6 +328,13 @@ 47589AEE1E332D5D0047DFCD /* IARError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IARError.swift; sourceTree = ""; }; 47589B531E333F450047DFCD /* TPInAppReceipt.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TPInAppReceipt.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 47589B551E3342490047DFCD /* DeviceGUIDRetriever.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceGUIDRetriever.swift; sourceTree = ""; }; + 476C64BD22BE6DC100D973F9 /* PCKS7.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PCKS7.swift; sourceTree = ""; }; + 476C64C322BFC76000D973F9 /* Example */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = Example; sourceTree = BUILT_PRODUCTS_DIR; }; + 476C64C522BFC76000D973F9 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; + 476C64D322C028D300D973F9 /* ASN1Object.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ASN1Object.swift; sourceTree = ""; }; + 476C64D522C028F800D973F9 /* ASN1Object+Helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ASN1Object+Helper.swift"; sourceTree = ""; }; + 476C64D722C0298000D973F9 /* ASN1Object+ValueReading.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ASN1Object+ValueReading.swift"; sourceTree = ""; }; + 476C64D922C0330500D973F9 /* ASN1Object+Sequence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ASN1Object+Sequence.swift"; sourceTree = ""; }; 479DC54C1DA0B8BB00D9A5E3 /* Date+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Date+Extension.swift"; sourceTree = ""; }; 47D2132E1E4588CF00994B00 /* libcrypto.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libcrypto.a; path = Vendor/OpenSSL/Mac/libcrypto.a; sourceTree = SOURCE_ROOT; }; 47D2132F1E4588CF00994B00 /* libssl.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libssl.a; path = Vendor/OpenSSL/Mac/libssl.a; sourceTree = SOURCE_ROOT; }; @@ -333,8 +366,19 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 47D213311E4588CF00994B00 /* libssl.a in Frameworks */, - 47D213301E4588CF00994B00 /* libcrypto.a in Frameworks */, + 476C64CE22BFCCB400D973F9 /* Security.framework in Frameworks */, + 476C64CF22BFCCD500D973F9 /* libcrypto.a in Frameworks */, + 476C64D022BFCCD500D973F9 /* libssl.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 476C64C022BFC76000D973F9 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 476C64CD22BFC9AA00D973F9 /* TPInAppReceipt.framework in Frameworks */, + 476C64D122BFCCDE00D973F9 /* libcrypto.a in Frameworks */, + 476C64D222BFCCDE00D973F9 /* libssl.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -355,6 +399,7 @@ 47209ACD1D9E92CC0010BCDE /* TPInAppReceipt.podspec */, 47209A031D9E0FD60010BCDE /* TPInAppReceipt */, 47209A0E1D9E0FD60010BCDE /* TPInAppReceiptTests */, + 476C64C422BFC76000D973F9 /* Example */, 47209A021D9E0FD60010BCDE /* Products */, 470D079B203B4FC600F3335F /* Frameworks */, ); @@ -366,6 +411,7 @@ 47209A011D9E0FD60010BCDE /* TPInAppReceipt.framework */, 47209A0A1D9E0FD60010BCDE /* TPInAppReceiptTests.xctest */, 47589B531E333F450047DFCD /* TPInAppReceipt.framework */, + 476C64C322BFC76000D973F9 /* Example */, ); name = Products; sourceTree = ""; @@ -503,13 +549,14 @@ 47209ABB1D9E111C0010BCDE /* Source */ = { isa = PBXGroup; children = ( + 476C64BC22BE6DB300D973F9 /* pcks7 */, + 4728B65722BE3CF800607E5E /* asn1 */, 47209ABF1D9E111C0010BCDE /* InAppReceiptManager.swift */, 47D213391E4738AB00994B00 /* Initialization.swift */, 47589AE41E319A220047DFCD /* Validation.swift */, 47209ABE1D9E111C0010BCDE /* InAppReceipt.swift */, 47589AEA1E32D6BB0047DFCD /* InAppReceiptPayload.swift */, 47589AE81E31B2F90047DFCD /* InAppPurchase.swift */, - 47209ABC1D9E111C0010BCDE /* ASN1Helper.swift */, 47589AE61E31AE6F0047DFCD /* PKCS7Wrapper.swift */, 47589AEE1E332D5D0047DFCD /* IARError.swift */, 47589B551E3342490047DFCD /* DeviceGUIDRetriever.swift */, @@ -519,6 +566,19 @@ path = Source; sourceTree = ""; }; + 4728B65722BE3CF800607E5E /* asn1 */ = { + isa = PBXGroup; + children = ( + 4728B65822BE3DB900607E5E /* Asn1Coder.swift */, + 47209ABC1D9E111C0010BCDE /* ASN1Helper.swift */, + 476C64D322C028D300D973F9 /* ASN1Object.swift */, + 476C64D522C028F800D973F9 /* ASN1Object+Helper.swift */, + 476C64D722C0298000D973F9 /* ASN1Object+ValueReading.swift */, + 476C64D922C0330500D973F9 /* ASN1Object+Sequence.swift */, + ); + name = asn1; + sourceTree = ""; + }; 47589B581E33590F0047DFCD /* iOS */ = { isa = PBXGroup; children = ( @@ -537,6 +597,22 @@ path = Mac; sourceTree = ""; }; + 476C64BC22BE6DB300D973F9 /* pcks7 */ = { + isa = PBXGroup; + children = ( + 476C64BD22BE6DC100D973F9 /* PCKS7.swift */, + ); + name = pcks7; + sourceTree = ""; + }; + 476C64C422BFC76000D973F9 /* Example */ = { + isa = PBXGroup; + children = ( + 476C64C522BFC76000D973F9 /* main.swift */, + ); + path = Example; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -763,13 +839,30 @@ productReference = 47589B531E333F450047DFCD /* TPInAppReceipt.framework */; productType = "com.apple.product-type.framework"; }; + 476C64C222BFC76000D973F9 /* Example */ = { + isa = PBXNativeTarget; + buildConfigurationList = 476C64C722BFC76000D973F9 /* Build configuration list for PBXNativeTarget "Example" */; + buildPhases = ( + 476C64BF22BFC76000D973F9 /* Sources */, + 476C64C022BFC76000D973F9 /* Frameworks */, + 476C64C122BFC76000D973F9 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Example; + productName = Example; + productReference = 476C64C322BFC76000D973F9 /* Example */; + productType = "com.apple.product-type.tool"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 472099F81D9E0FD60010BCDE /* Project object */ = { isa = PBXProject; attributes = { - LastSwiftUpdateCheck = 0800; + LastSwiftUpdateCheck = 1020; LastUpgradeCheck = 1020; ORGANIZATIONNAME = "Pavel Tikhonenko"; TargetAttributes = { @@ -783,6 +876,14 @@ LastSwiftMigration = 1020; ProvisioningStyle = Automatic; }; + 47589AF11E333F450047DFCD = { + LastSwiftMigration = 1020; + }; + 476C64C222BFC76000D973F9 = { + CreatedOnToolsVersion = 10.2.1; + DevelopmentTeam = Y357EKMWLB; + ProvisioningStyle = Automatic; + }; }; }; buildConfigurationList = 472099FB1D9E0FD60010BCDE /* Build configuration list for PBXProject "TPInAppReceipt" */; @@ -801,6 +902,7 @@ 47209A001D9E0FD60010BCDE /* TPInAppReceipt iOS */, 47589AF11E333F450047DFCD /* TPInAppReceipt macOS */, 47209A091D9E0FD60010BCDE /* TPInAppReceiptTests */, + 476C64C222BFC76000D973F9 /* Example */, ); }; /* End PBXProject section */ @@ -839,9 +941,14 @@ files = ( 47589AEB1E32D6BB0047DFCD /* InAppReceiptPayload.swift in Sources */, 47589AEF1E332D5E0047DFCD /* IARError.swift in Sources */, + 476C64D822C0298000D973F9 /* ASN1Object+ValueReading.swift in Sources */, + 476C64BE22BE6DC100D973F9 /* PCKS7.swift in Sources */, + 476C64D422C028D300D973F9 /* ASN1Object.swift in Sources */, 479DC54D1DA0B8BB00D9A5E3 /* Date+Extension.swift in Sources */, 47D2133A1E4738AB00994B00 /* Initialization.swift in Sources */, 47589AE91E31B2F90047DFCD /* InAppPurchase.swift in Sources */, + 476C64DA22C0330500D973F9 /* ASN1Object+Sequence.swift in Sources */, + 476C64D622C028F800D973F9 /* ASN1Object+Helper.swift in Sources */, 47209AC01D9E111C0010BCDE /* ASN1Helper.swift in Sources */, 47209AC11D9E111C0010BCDE /* Data+Extension.swift in Sources */, 47209AC21D9E111C0010BCDE /* InAppReceipt.swift in Sources */, @@ -849,6 +956,7 @@ 47589B561E3342490047DFCD /* DeviceGUIDRetriever.swift in Sources */, 47209AC31D9E111C0010BCDE /* InAppReceiptManager.swift in Sources */, 47589AE71E31AE6F0047DFCD /* PKCS7Wrapper.swift in Sources */, + 4728B65922BE3DB900607E5E /* Asn1Coder.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -864,18 +972,28 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 476C64CC22BFC94400D973F9 /* ASN1Helper.swift in Sources */, 47589AF31E333F450047DFCD /* InAppReceiptPayload.swift in Sources */, 47589AF41E333F450047DFCD /* IARError.swift in Sources */, + 476C64CA22BFC93E00D973F9 /* PCKS7.swift in Sources */, 47589AF51E333F450047DFCD /* Date+Extension.swift in Sources */, 47D2133B1E4738AB00994B00 /* Initialization.swift in Sources */, 47589AF61E333F450047DFCD /* InAppPurchase.swift in Sources */, 47589B571E3342490047DFCD /* DeviceGUIDRetriever.swift in Sources */, - 47589AF81E333F450047DFCD /* ASN1Helper.swift in Sources */, 47589AF91E333F450047DFCD /* Data+Extension.swift in Sources */, 47589AFA1E333F450047DFCD /* InAppReceipt.swift in Sources */, 47589AFB1E333F450047DFCD /* Validation.swift in Sources */, 47589AFC1E333F450047DFCD /* InAppReceiptManager.swift in Sources */, 47589AFD1E333F450047DFCD /* PKCS7Wrapper.swift in Sources */, + 476C64CB22BFC94400D973F9 /* Asn1Coder.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 476C64BF22BFC76000D973F9 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 476C64C622BFC76000D973F9 /* main.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1012,12 +1130,16 @@ 47209A161D9E0FD60010BCDE /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - HEADER_SEARCH_PATHS = "$(SRCROOT)/Vendor/OpenSSL/include"; + HEADER_SEARCH_PATHS = ( + "$(SRCROOT)/Vendor/OpenSSL/include", + "$(SRCROOT)/Vendor/ssh1/include", + ); INFOPLIST_FILE = TPInAppReceipt/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; @@ -1028,7 +1150,8 @@ PRODUCT_BUNDLE_IDENTIFIER = com.tikhop.TPInAppReceipt; PRODUCT_NAME = TPInAppReceipt; SKIP_INSTALL = YES; - SWIFT_INCLUDE_PATHS = "$(SRCROOT)/Vendor/OpenSSL"; + SWIFT_INCLUDE_PATHS = "$(SRCROOT)/Vendor/OpenSSL $(SRCROOT)/Vendor/ssh1"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; }; name = Debug; @@ -1036,12 +1159,16 @@ 47209A171D9E0FD60010BCDE /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - HEADER_SEARCH_PATHS = "$(SRCROOT)/Vendor/OpenSSL/include"; + HEADER_SEARCH_PATHS = ( + "$(SRCROOT)/Vendor/OpenSSL/include", + "$(SRCROOT)/Vendor/ssh1/include", + ); INFOPLIST_FILE = TPInAppReceipt/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; @@ -1052,7 +1179,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.tikhop.TPInAppReceipt; PRODUCT_NAME = TPInAppReceipt; SKIP_INSTALL = YES; - SWIFT_INCLUDE_PATHS = "$(SRCROOT)/Vendor/OpenSSL"; + SWIFT_INCLUDE_PATHS = "$(SRCROOT)/Vendor/OpenSSL $(SRCROOT)/Vendor/ssh1"; SWIFT_VERSION = 5.0; }; name = Release; @@ -1084,12 +1211,16 @@ 47589B511E333F450047DFCD /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - HEADER_SEARCH_PATHS = "$(SRCROOT)/Vendor/OpenSSL/include"; + HEADER_SEARCH_PATHS = ( + "$(SRCROOT)/Vendor/OpenSSL/include", + "$(SRCROOT)/Vendor/ssh1", + ); INFOPLIST_FILE = "$(SRCROOT)/TPInAppReceipt/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; @@ -1097,12 +1228,14 @@ "$(inherited)", "$(PROJECT_DIR)/Vendor/OpenSSL/Mac", ); + MACH_O_TYPE = mh_dylib; MACOSX_DEPLOYMENT_TARGET = 10.11; PRODUCT_BUNDLE_IDENTIFIER = com.tikhop.TPInAppReceipt; PRODUCT_NAME = TPInAppReceipt; SDKROOT = macosx; SKIP_INSTALL = YES; - SWIFT_INCLUDE_PATHS = "$(SRCROOT)/Vendor/OpenSSL"; + SWIFT_INCLUDE_PATHS = "$(SRCROOT)/Vendor/OpenSSL $(SRCROOT)/Vendor/ssh1"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; }; name = Debug; @@ -1110,12 +1243,16 @@ 47589B521E333F450047DFCD /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - HEADER_SEARCH_PATHS = "$(SRCROOT)/Vendor/OpenSSL/include"; + HEADER_SEARCH_PATHS = ( + "$(SRCROOT)/Vendor/OpenSSL/include", + "$(SRCROOT)/Vendor/ssh1", + ); INFOPLIST_FILE = "$(SRCROOT)/TPInAppReceipt/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; @@ -1123,12 +1260,60 @@ "$(inherited)", "$(PROJECT_DIR)/Vendor/OpenSSL/Mac", ); + MACH_O_TYPE = mh_dylib; MACOSX_DEPLOYMENT_TARGET = 10.11; PRODUCT_BUNDLE_IDENTIFIER = com.tikhop.TPInAppReceipt; PRODUCT_NAME = TPInAppReceipt; SDKROOT = macosx; SKIP_INSTALL = YES; - SWIFT_INCLUDE_PATHS = "$(SRCROOT)/Vendor/OpenSSL"; + SWIFT_INCLUDE_PATHS = "$(SRCROOT)/Vendor/OpenSSL $(SRCROOT)/Vendor/ssh1"; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 476C64C822BFC76000D973F9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "Mac Developer"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = Y357EKMWLB; + GCC_C_LANGUAGE_STANDARD = gnu11; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Vendor/OpenSSL/Mac", + ); + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 476C64C922BFC76000D973F9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "Mac Developer"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = Y357EKMWLB; + GCC_C_LANGUAGE_STANDARD = gnu11; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Vendor/OpenSSL/Mac", + ); + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_FAST_MATH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; SWIFT_VERSION = 5.0; }; name = Release; @@ -1172,6 +1357,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 476C64C722BFC76000D973F9 /* Build configuration list for PBXNativeTarget "Example" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 476C64C822BFC76000D973F9 /* Debug */, + 476C64C922BFC76000D973F9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ }; rootObject = 472099F81D9E0FD60010BCDE /* Project object */; diff --git a/TPInAppReceipt/Source/ASN1Helper.swift b/TPInAppReceipt/Source/ASN1Helper.swift index b6b97dc..f17a5c4 100644 --- a/TPInAppReceipt/Source/ASN1Helper.swift +++ b/TPInAppReceipt/Source/ASN1Helper.swift @@ -9,6 +9,14 @@ import Foundation import openssl +public struct InAppReceiptAttribute +{ + var type: Int! + var version: Int! + var value: ASN1Object! +} + + func asn1ConsumeObject(_ ptr: UnsafeMutablePointer?>, _ l: Int) { var pClass: Int32 = 0 diff --git a/TPInAppReceipt/Source/ASN1Object+Helper.swift b/TPInAppReceipt/Source/ASN1Object+Helper.swift new file mode 100644 index 0000000..a0d68e5 --- /dev/null +++ b/TPInAppReceipt/Source/ASN1Object+Helper.swift @@ -0,0 +1,92 @@ +// +// ASN1Object+Helper.swift +// TPInAppReceipt iOS +// +// Created by Pavel Tikhonenko on 24/06/2019. +// Copyright © 2019 Pavel Tikhonenko. All rights reserved. +// + +import Foundation + +/// +/// Utils methods +extension ASN1Object +{ + static func initializeASN1Object(from data: Data) throws -> ASN1Object + { + guard isDataValid(data) else + { + throw ASN1Error.initializationFailed(reason: .dataIsInvalid) + } + + return ASN1Object(data: data) + } + + static func isDataValid(_ data: Data) -> Bool + { + let c = data.count + + if c == 0 { return false } + + + guard let identifier = try? Identifier(data: data) else + { + return false + } + + var bytesCount = 1 + + let length = ASN1Object.extractLenght(from: data.pointer.advanced(by: 1)) + bytesCount += (length.offset + length.value) + + if c != bytesCount + { + return false + } + + return true + } + + static func isPointerValid(_ pointer: UnsafePointer) -> Bool + { + return true + } + + static func extractLenght(from data: Data) -> Length + { + guard let firstByte = data.first else + { + return Length.short(value: 0) + } + + if ((firstByte & 0x80) != 0) + { + let l: Int = Int(firstByte - 0x80) + + let lData = data.dropLast(data.count - 1 - l).advanced(by: 1) + let lResult = UnsafeMutableBufferPointer.allocate(capacity: 1) + lData.copyBytes(to: lResult) + let r = lResult.first! + lResult.deallocate() + + return Length.long(length: l, value: r) + }else{ + return Length.short(value: Int(firstByte)) + } + } + + static func extractLenght(from pointer: UnsafePointer) -> Length + { + let firstByte = pointer[0] + + if ((firstByte & 0x80) != 0) + { + let l: Int = Int(firstByte - 0x80) + let nextOctet = pointer.advanced(by: 1) + + return Length.long(length: l, value: readInt(from: nextOctet, l: l)) + }else{ + return Length.short(value: Int(firstByte)) + } + } +} diff --git a/TPInAppReceipt/Source/ASN1Object+Sequence.swift b/TPInAppReceipt/Source/ASN1Object+Sequence.swift new file mode 100644 index 0000000..d9d7a6b --- /dev/null +++ b/TPInAppReceipt/Source/ASN1Object+Sequence.swift @@ -0,0 +1,59 @@ +// +// ASN1Object+Sequence.swift +// TPInAppReceipt iOS +// +// Created by Pavel Tikhonenko on 24/06/2019. +// Copyright © 2019 Pavel Tikhonenko. All rights reserved. +// + +import Foundation + +struct ASN1Iterator: IteratorProtocol +{ + typealias Element = ASN1Object + + let asn1: ASN1Object + var lastItem: ASN1Object + var bytesLeft: Int = 0 + + init(_ asn1: ASN1Object) + { + self.asn1 = asn1 + self.lastItem = asn1 + self.bytesLeft = asn1.length.value + } + + mutating func next() -> Element? + { + guard asn1.identifier.encodingType == .constructed, bytesLeft > 0 else + { + return nil + } + + var contents: UnsafePointer = lastItem.pointer + contents = contents.advanced(by: 1) //Identifier + contents = contents.advanced(by: lastItem.length.offset) + + if bytesLeft != asn1.length.value + { + contents = contents.advanced(by: lastItem.length.value) + } + + let asn1 = ASN1Object(bytes: contents) + lastItem = asn1 + + bytesLeft -= asn1.bytesCount + + return asn1 + } +} + +extension ASN1Object: Sequence +{ + func makeIterator() -> ASN1Iterator + { + return ASN1Iterator(self) + } + + typealias Element = ASN1Object +} diff --git a/TPInAppReceipt/Source/ASN1Object+ValueReading.swift b/TPInAppReceipt/Source/ASN1Object+ValueReading.swift new file mode 100644 index 0000000..4d1f8ec --- /dev/null +++ b/TPInAppReceipt/Source/ASN1Object+ValueReading.swift @@ -0,0 +1,159 @@ +// +// ASN1Object+ValueReading.swift +// TPInAppReceipt iOS +// +// Created by Pavel Tikhonenko on 24/06/2019. +// Copyright © 2019 Pavel Tikhonenko. All rights reserved. +// + +import Foundation + +extension ASN1Object +{ + static func readString(from contents: UnsafePointer, _ l: Int, encoding: String.Encoding) -> String + { + let data = Data(bytes: contents, count: l) + return String(data: data, encoding: encoding) ?? "" + } + + static func readInt(from contents: UnsafePointer, l: Int) -> Int + { + var r: UInt64 = 0 + + for i in 0..= Int.max + { + return -1 + } + + return Int(r) + } + + static func asn1ReadUTF8String(_ ptr: UnsafePointer, _ l: Int) -> String? + { + return readString(from: ptr, l, encoding: .utf8) + } + + static func asn1ReadASCIIString(_ ptr: UnsafePointer, _ l: Int) -> String? + { + return readString(from: ptr, l, encoding: .ascii) + } + + + func extractValue() -> Any? + { + return value() + } + + fileprivate func contentsBytes() -> UnsafePointer + { + var contents: UnsafePointer = pointer + contents = contents.advanced(by: 1) //Identifier + contents = contents.advanced(by: length.offset) //Identifier + return contents + } + + fileprivate func value() -> ASN1ExtractableValueTypes? + { + let type = identifier.type + + guard type != .unknown else + { + return nil + } + + let contents: UnsafePointer = contentsBytes() + let l = length.value + + switch type + { + case .integer: + return ASN1Object.readInt(from: contents, l: l) + case .octetString: + let data = Data(bytes: contents, count: l) + if let asn1 = try? ASN1Object.initializeASN1Object(from: data) + { + return asn1 + }else{ + return Data(bytes: contents, count: l) + } + case .endOfContent: + return nil + case .boolean: + return true + case .bitString: + return "" + case .null: + return nil + case .objectIdentifier: + return "objectIdentifier" + case .objectDescriptor: + return "objectIdentifier" + case .external: + return "external" + case .real: + return "real" + case .enumerated: + return "enumerated" + case .embeddedPdv: + return "embeddedPdv" + case .utf8String: + return ASN1Object.readString(from: contents, l, encoding: .utf8) + case .relativeOid: + return "relativeOid" + case .sequence: + if let asn1 = try? ASN1Object.initializeASN1Object(from: Data(bytes: contents, count: l)) + { + return asn1 + }else{ + return "sequence" + } + + case .set: + if let asn1 = try? ASN1Object.initializeASN1Object(from: Data(bytes: contents, count: l)) + { + return asn1 + }else{ + return "set" + } + case .numericString: + return "numericString" + case .printableString: + return "printableString" + case .t61String: + return "t61String" + case .videotexString: + return "videotexString" + case .ia5String: + return ASN1Object.readString(from: contents, l, encoding: .ascii) + case .utcTime: + return "utcTime" + case .generalizedTime: + return "generalizedTime" + case .graphicString: + return "graphicString" + case .visibleString: + return "visibleString" + case .generalString: + return "generalString" + case .universalString: + return "universalString" + case .characterString: + return "characterString" + case .bmpString: + return "bmpString" + default: + return nil + } + return Data() + } +} diff --git a/TPInAppReceipt/Source/ASN1Object.swift b/TPInAppReceipt/Source/ASN1Object.swift new file mode 100644 index 0000000..aca71f3 --- /dev/null +++ b/TPInAppReceipt/Source/ASN1Object.swift @@ -0,0 +1,9 @@ +// +// ASN1Object.swift +// TPInAppReceipt iOS +// +// Created by Pavel Tikhonenko on 24/06/2019. +// Copyright © 2019 Pavel Tikhonenko. All rights reserved. +// + +import Foundation diff --git a/TPInAppReceipt/Source/Asn1Coder.swift b/TPInAppReceipt/Source/Asn1Coder.swift new file mode 100644 index 0000000..2b328ec --- /dev/null +++ b/TPInAppReceipt/Source/Asn1Coder.swift @@ -0,0 +1,239 @@ +// +// Asn1Coder.swift +// TPInAppReceipt iOS +// +// Created by Pavel Tikhonenko on 22/06/2019. +// Copyright © 2019 Pavel Tikhonenko. All rights reserved. +// + +import Foundation + +class ASN1Coder +{ + func decode() + { + + } +} + + + +extension ASN1Object +{ + var type: ASN1Object.Identifier.`Type` + { + return identifier.type + } +} + +struct ASN1Object +{ + let identifier: Identifier + var length: Length + + var rawData: Data! //Might be nil in this case use pointer + var pointer: UnsafePointer //Always awailable + var bytesCount: Int + + enum Length + { + case short(value: Int) + case long(length: Int, value: Int) + } + + struct Identifier + { + public enum Class: UInt8 + { + case universal = 0 + case application = 1 + case contextSpecific = 2 + case `private` = 3 + } + + public enum `Type`: UInt8 + { + case endOfContent = 0x00 + case boolean = 1 + case integer = 2 + case bitString = 3 + case octetString = 4 + case null = 5 + case objectIdentifier = 6 + case objectDescriptor = 7 + case external = 8 + case real = 9 + case enumerated = 10 + case embeddedPdv = 11 + case utf8String = 12 + case relativeOid = 13 + case sequence = 16 + case set = 17 + case numericString = 18 + case printableString = 19 + case t61String = 20 + case videotexString = 21 + case ia5String = 22 + case utcTime = 23 + case generalizedTime = 24 + case graphicString = 25 + case visibleString = 26 + case generalString = 27 + case universalString = 28 + case characterString = 29 + case bmpString = 30 + case unknown = 126 + } + + public enum EncodingType: UInt8 + { + case primitive = 0 + case constructed = 1 + } + + let `class`: Class + let encodingType: EncodingType + var tagNumber: UInt8 + + var type: `Type` { return Type(rawValue: tagNumber) ?? .unknown } + + let raw: UInt8 + + init(data: Data) throws + { + try self.init(raw: data.uint8) + } + + init(raw: UInt8) throws + { + self.raw = raw + self.tagNumber = raw & 0b11111 + + guard let c = Class(rawValue: (raw >> 5) & 0b11), let e = EncodingType(rawValue: (raw >> 4) & 0b1) else + { + throw ASN1Error.initializationFailed(reason: .dataIsInvalid) + } + + self.class = c + self.encodingType = e + + guard type != .unknown else + { + throw ASN1Error.initializationFailed(reason: .dataIsInvalid) + } + } + } +} + +extension ASN1Object +{ + //Using this initialization method we assume that data containt a proper asn1 object as defined by ITU-T X.690 + init(data: Data) + { + rawData = data + bytesCount = 1 + pointer = rawData.pointer + identifier = try! Identifier(data: data) + length = .short(value: 0) + length = ASN1Object.extractLenght(from: pointer.advanced(by: 1)) + bytesCount += (length.offset + length.value) + } + + //Using this initialization method we assume that pointer to asn1 object containt a proper asn1 object as defined by ITU-T X.690 + init(bytes: UnsafePointer) + { + pointer = bytes + bytesCount = 1 + identifier = try! Identifier(raw: pointer[0]) + length = .short(value: 0) + length = ASN1Object.extractLenght(from: pointer.advanced(by: 1)) + bytesCount += (length.offset + length.value) + } +} + + +extension ASN1Object.Identifier +{ + var isPrimitive: Bool + { + return encodingType == .primitive + } + + var isConstructed: Bool + { + return encodingType == .constructed + } +} + +extension ASN1Object.Length +{ + var value: Int + { + switch self + { + case .long(_, let value): + return value + case .short(let value): + return value + } + } + + var offset: Int + { + switch self + { + + case .long(let length, _): + return 1 + length + default: + return 1 + } + } +} + +//Value Data Types we expect from ASN1 +protocol ASN1ExtractableValueTypes {} + +extension ASN1Object: ASN1ExtractableValueTypes { } +extension Bool: ASN1ExtractableValueTypes { } +extension Data: ASN1ExtractableValueTypes { } +extension String: ASN1ExtractableValueTypes { } +extension Date: ASN1ExtractableValueTypes { } +extension Int: ASN1ExtractableValueTypes { } + + +/// `ASN1Error` +public enum ASN1Error: Error +{ + case initializationFailed(reason: InitializationFailureReason) + case validationFailed(reason: ValidationFailureReason) + + + /// The underlying reason the receipt initialization error occurred. + /// + /// - dataIsInvalid: Provided data don't contain any asn1 object + public enum InitializationFailureReason + { + case dataIsInvalid + } + + /// The underlying reason the receipt validation error occurred. + /// + /// - hashValidation: Computed hash doesn't match the hash from the receipt's payload + /// - signatureValidation: Error occurs during signature validation. It has several reasons to failure + public enum ValidationFailureReason + { + case hashValidation + case signatureValidation(SignatureValidationFailureReason) + } + + /// The underlying reason the signature validation error occurred. + /// + /// - rootCertificateNotFound: Apple Inc Root Certificate Not Found + /// - invalidSignature: The receipt contains invalid signature + public enum SignatureValidationFailureReason + { + case rootCertificateNotFound + case invalidSignature + } +} diff --git a/TPInAppReceipt/Source/Data+Extension.swift b/TPInAppReceipt/Source/Data+Extension.swift index 5ff446f..9aac742 100644 --- a/TPInAppReceipt/Source/Data+Extension.swift +++ b/TPInAppReceipt/Source/Data+Extension.swift @@ -13,14 +13,58 @@ public typealias ASN1Attribute = (data: Data, type: Int) public extension Data { - public var pointer: UnsafePointer + var pointer: UnsafePointer { var bytes = [UInt8](repeating:0, count: self.count) copyBytes(to: &bytes, count: self.count) return UnsafePointer(bytes) } - public func enumerateASN1Attributes(withBlock block: (ASN1Attribute) -> ()) + func enumerateASN1AttributesNoOpenssl(withBlock block: (InAppReceiptAttribute) -> ()) + { + let asn1Object = ASN1Object(data: self) + + var i = 0 + for item in asn1Object.enumerated() + { + var attr = InAppReceiptAttribute() + i += 1 + for i in item.element.enumerated() + { + let type = i.element.identifier.type + + guard type != .unknown else + { + continue + } + + switch type + { + case .integer: + if let value = i.element.extractValue() as? Int + { + if attr.type == nil + { + attr.type = value + }else{ + attr.version = value + } + } + break + case .octetString: + attr.value = i.element + default: + continue + } + } + + block(attr) + } + + + } + + func enumerateASN1Attributes(withBlock block: (ASN1Attribute) -> ()) { var type: Int32 = 0 var tag: Int32 = 0 @@ -55,7 +99,6 @@ public extension Data // Skip attribute version asn1ConsumeObject(&ptr, sequenceEnd - ptr!) - // Check the attribute value let data = asn1ReadOctectString(&ptr, sequenceEnd - ptr!) block((data, attributeType)) @@ -66,5 +109,20 @@ public extension Data ptr = ptr?.advanced(by: length) } } + + + } +} + +extension Data +{ + var uint8: UInt8 + { + get + { + var number: UInt8 = 0 + self.copyBytes(to: &number, count: MemoryLayout.size) + return number + } } } diff --git a/TPInAppReceipt/Source/IARError.swift b/TPInAppReceipt/Source/IARError.swift index cbb8e59..f2c293c 100644 --- a/TPInAppReceipt/Source/IARError.swift +++ b/TPInAppReceipt/Source/IARError.swift @@ -53,6 +53,4 @@ public enum IARError: Error case receiptSignedDataNotFound case invalidSignature } - - } diff --git a/TPInAppReceipt/Source/InAppReceipt.swift b/TPInAppReceipt/Source/InAppReceipt.swift index efde09e..f25e83e 100644 --- a/TPInAppReceipt/Source/InAppReceipt.swift +++ b/TPInAppReceipt/Source/InAppReceipt.swift @@ -17,6 +17,7 @@ public enum InAppReceiptField: Int case inAppPurchaseReceipt = 17 // The receipt for an in-app purchase. case originalAppVersion = 19 case expirationDate = 21 + case receiptCreationDate = 12 case quantity = 1701 case productIdentifier = 1702 @@ -51,46 +52,51 @@ public struct InAppReceipt /// /// - parameter pkcs7: `PKCS7Wrapper` pkcs7 container of the receipt init(pkcs7: PKCS7Wrapper) + { + self.init(pkcs7: pkcs7, payload: InAppReceiptPayload(asn1Data: pkcs7.extractASN1Data())) + } + + init(pkcs7: PKCS7Wrapper, payload: InAppReceiptPayload) { self.pkcs7Container = pkcs7 - self.payload = InAppReceiptPayload(asn1Data: pkcs7.extractASN1Data()) + self.payload = payload } } public extension InAppReceipt { /// The app’s bundle identifier - public var bundleIdentifier: String + var bundleIdentifier: String { return payload.bundleIdentifier } /// The app’s version number - public var appVersion: String + var appVersion: String { return payload.appVersion } /// The version of the app that was originally purchased. - public var originalAppVersion: String + var originalAppVersion: String { return payload.originalAppVersion } /// In-app purchase's receipts - public var purchases: [InAppPurchase] + var purchases: [InAppPurchase] { return payload.purchases } /// The date that the app receipt expires - public var expirationDate: String? + var expirationDate: String? { return payload.expirationDate } /// Returns `true` if any purchases exist, `false` otherwise - public var hasPurchases: Bool + var hasPurchases: Bool { return purchases.count > 0 } @@ -98,7 +104,7 @@ public extension InAppReceipt /// Return original transaction identifier if there is a purchase for a specific product identifier /// /// - parameter productIdentifier: Product name - public func originalTransactionIdentifier(ofProductIdentifier productIdentifier: String) -> String? + func originalTransactionIdentifier(ofProductIdentifier productIdentifier: String) -> String? { return purchases(ofProductIdentifier: productIdentifier).first?.originalTransactionIdentifier } @@ -106,7 +112,7 @@ public extension InAppReceipt /// Returns `true` if there is a purchase for a specific product identifier, `false` otherwise /// /// - parameter productIdentifier: Product name - public func containsPurchase(ofProductIdentifier productIdentifier: String) -> Bool + func containsPurchase(ofProductIdentifier productIdentifier: String) -> Bool { for item in purchases { @@ -124,7 +130,7 @@ public extension InAppReceipt /// /// - parameter productIdentifier: Product name /// - parameter sort: Sorting block - public func purchases(ofProductIdentifier productIdentifier: String, + func purchases(ofProductIdentifier productIdentifier: String, sortedBy sort: ((InAppPurchase, InAppPurchase) -> Bool)? = nil) -> [InAppPurchase] { let filtered: [InAppPurchase] = purchases.filter({ @@ -149,7 +155,7 @@ public extension InAppReceipt /// `nil` otherwise /// /// - parameter productIdentifier: Product name - public func activeAutoRenewableSubscriptionPurchases(ofProductIdentifier productIdentifier: String, forDate date: Date) -> InAppPurchase? + func activeAutoRenewableSubscriptionPurchases(ofProductIdentifier productIdentifier: String, forDate date: Date) -> InAppPurchase? { let filtered = purchases(ofProductIdentifier: productIdentifier) @@ -170,7 +176,7 @@ public extension InAppReceipt /// /// - parameter productIdentifier: Product name /// - parameter date: Date to check subscription against - public func hasActiveAutoRenewableSubscription(ofProductIdentifier productIdentifier: String, forDate date: Date) -> Bool + func hasActiveAutoRenewableSubscription(ofProductIdentifier productIdentifier: String, forDate date: Date) -> Bool { return activeAutoRenewableSubscriptionPurchases(ofProductIdentifier: productIdentifier, forDate: date) != nil } @@ -179,22 +185,20 @@ public extension InAppReceipt internal extension InAppReceipt { /// Used to validate the receipt - internal var bundleIdentifierData: Data + var bundleIdentifierData: Data { return payload.bundleIdentifierData } /// An opaque value used, with other data, to compute the SHA-1 hash during validation. - internal var opaqueValue: Data + var opaqueValue: Data { return payload.opaqueValue } /// A SHA-1 hash, used to validate the receipt. - internal var receiptHash: Data + var receiptHash: Data { return payload.receiptHash } - - } diff --git a/TPInAppReceipt/Source/InAppReceiptPayload.swift b/TPInAppReceipt/Source/InAppReceiptPayload.swift index 0e61b0f..8bfd9f6 100644 --- a/TPInAppReceipt/Source/InAppReceiptPayload.swift +++ b/TPInAppReceipt/Source/InAppReceiptPayload.swift @@ -34,6 +34,9 @@ public struct InAppReceiptPayload /// A SHA-1 hash, used to validate the receipt. public let receiptHash: Data + /// The date when the app receipt was created. + public let receiptCreationDate: String + /// Initialize a `InAppReceipt` with asn1 payload /// /// - parameter asn1Data: `Data` object that represents receipt's payload @@ -47,6 +50,7 @@ public struct InAppReceiptPayload var opaqueValue = Data() var receiptHash = Data() var expirationDate: String? = "" + var receiptCreationDate: String = "" asn1Data.enumerateASN1Attributes { (attributes) in if let field = InAppReceiptField(rawValue: attributes.type) @@ -70,22 +74,24 @@ public struct InAppReceiptPayload case .receiptHash: receiptHash = Data(bytes: bytes, count: length) case .inAppPurchaseReceipt: - purchases.append(InAppPurchase(asn1Data: attributes.data)) + break //purchases.append(InAppPurchase(asn1Data: attributes.data)) case .originalAppVersion: originalAppVersion = asn1ReadUTF8String(&ptr, bytes.count)! case .expirationDate: let str = asn1ReadASCIIString(&ptr, bytes.count) expirationDate = str + case .receiptCreationDate: + receiptCreationDate = asn1ReadASCIIString(&ptr, bytes.count)! default: print("attribute.type = \(attributes.type))") } } } - self.init(bundleIdentifier: bundleIdentifier, appVersion: appVersion, originalAppVersion: originalAppVersion, purchases: purchases, expirationDate: expirationDate, bundleIdentifierData: bundleIdentifierData, opaqueValue: opaqueValue, receiptHash: receiptHash) + self.init(bundleIdentifier: bundleIdentifier, appVersion: appVersion, originalAppVersion: originalAppVersion, purchases: purchases, expirationDate: expirationDate, bundleIdentifierData: bundleIdentifierData, opaqueValue: opaqueValue, receiptHash: receiptHash, receiptCreationDate: receiptCreationDate) } - fileprivate init(bundleIdentifier: String, appVersion: String, originalAppVersion: String, purchases: [InAppPurchase], expirationDate: String?, bundleIdentifierData: Data, opaqueValue: Data, receiptHash: Data) + init(bundleIdentifier: String, appVersion: String, originalAppVersion: String, purchases: [InAppPurchase], expirationDate: String?, bundleIdentifierData: Data, opaqueValue: Data, receiptHash: Data, receiptCreationDate: String) { self.bundleIdentifier = bundleIdentifier self.appVersion = appVersion @@ -95,5 +101,60 @@ public struct InAppReceiptPayload self.bundleIdentifierData = bundleIdentifierData self.opaqueValue = opaqueValue self.receiptHash = receiptHash + self.receiptCreationDate = receiptCreationDate + } +} + + +public extension InAppReceiptPayload +{ + init(noOpenSslData asn1Data: Data) + { + var bundleIdentifier = "" + var appVersion = "" + var originalAppVersion = "" + var purchases = [InAppPurchase]() + var bundleIdentifierData = Data() + var opaqueValue = Data() + var receiptHash = Data() + var expirationDate: String? = "" + var receiptCreationDate: String = "" + + asn1Data.enumerateASN1AttributesNoOpenssl { (attribute) in + if let field = InAppReceiptField(rawValue: attribute.type) + { + var value = attribute.value.extractValue() + + if let v = value as? ASN1Object + { + value = v.extractValue() + } + + switch (field) + { + case .bundleIdentifier: + bundleIdentifier = value as! String + bundleIdentifierData = bundleIdentifier.data(using: .utf8)! + case .appVersion: + appVersion = value as! String + case .opaqueValue: + opaqueValue = value as! Data + case .receiptHash: + receiptHash = value as! Data + case .inAppPurchaseReceipt: + break + case .originalAppVersion: + originalAppVersion = value as! String + case .expirationDate: + expirationDate = value as? String + case .receiptCreationDate: + receiptCreationDate = value as! String + default: + print("attribute.type = \(String(describing: attribute.type)))") + } + } + } + + self.init(bundleIdentifier: bundleIdentifier, appVersion: appVersion, originalAppVersion: originalAppVersion, purchases: purchases, expirationDate: expirationDate, bundleIdentifierData: bundleIdentifierData, opaqueValue: opaqueValue, receiptHash: receiptHash, receiptCreationDate: receiptCreationDate) } } diff --git a/TPInAppReceipt/Source/PCKS7.swift b/TPInAppReceipt/Source/PCKS7.swift new file mode 100644 index 0000000..2e8efa6 --- /dev/null +++ b/TPInAppReceipt/Source/PCKS7.swift @@ -0,0 +1,43 @@ +// +// PCKS7.swift +// TPInAppReceipt iOS +// +// Created by Pavel Tikhonenko on 22/06/2019. +// Copyright © 2019 Pavel Tikhonenko. All rights reserved. +// + +import Foundation + +//struct PCKS7 +//{ +// var data: PCKS7 +// var signedData: PCKS7 { get set } +// var signedData: Bool { get set } +// +// init(isAlive: Bool) +// init(isDead: Bool) +// +// enum OID: String +// { +// case data = "1.2.840.113549.1.7.1" +// case signedData = "1.2.840.113549.1.7.2" +// case envelopedData = "1.2.840.113549.1.7.3" +// case signedAndEnvelopedData = "1.2.840.113549.1.7.4" +// case digestedData = "1.2.840.113549.1.7.5" +// case encryptedData = "1.2.840.113549.1.7.6" +// } +//} + +//data OBJECT IDENTIFIER ::= { pkcs-7 1 } +//signedData OBJECT IDENTIFIER ::= { pkcs-7 2 } +//envelopedData OBJECT IDENTIFIER ::= { pkcs-7 3 } +//signedAndEnvelopedData OBJECT IDENTIFIER ::= { pkcs-7 4 } +//digestedData OBJECT IDENTIFIER ::= { pkcs-7 5 } +//encryptedData OBJECT IDENTIFIER ::= { pkcs-7 6 } + +//1.2.840.113549.1.7.1 - data +//1.2.840.113549.1.7.2 - signedData +//1.2.840.113549.1.7.3 - envelopedData +//1.2.840.113549.1.7.4 - signedAndEnvelopedData +//1.2.840.113549.1.7.5 - digestedData +//1.2.840.113549.1.7.6 - encryptedData diff --git a/TPInAppReceipt/Source/Temp b/TPInAppReceipt/Source/Temp new file mode 100644 index 0000000..e69de29 diff --git a/TPInAppReceiptTests/InAppReceiptTests.swift b/TPInAppReceiptTests/InAppReceiptTests.swift index 34e8b48..9bda9a0 100644 --- a/TPInAppReceiptTests/InAppReceiptTests.swift +++ b/TPInAppReceiptTests/InAppReceiptTests.swift @@ -9,85 +9,110 @@ import openssl class InAppReceiptTests: XCTestCase { - func testActiveAutoRenewableSubscriptionPurchasesWithoutCancellation() { - - // Given - let purchase1 = InAppPurchase(webOrderLineItemID: 1, originalPurchaseDateString: "2017-02-01T07:03:18Z", purchaseDateString: "2017-02-01T07:03:16Z", subscriptionExpirationDateString: "2017-02-01T07:06:16Z", cancellationDateString: "") - let purchase2 = InAppPurchase(webOrderLineItemID: 2, originalPurchaseDateString: "2017-02-01T21:26:12Z", purchaseDateString: "2017-02-01T21:26:11Z", subscriptionExpirationDateString: "2017-02-01T21:29:11Z", cancellationDateString: "") - let purchase3 = InAppPurchase(webOrderLineItemID: 3, originalPurchaseDateString: "2017-02-01T21:28:41Z", purchaseDateString: "2017-02-01T21:29:11Z", subscriptionExpirationDateString: "2017-02-01T21:32:11Z", cancellationDateString: "") - let receiptPayload: InAppReceiptPayload = InAppReceiptPayload(purchases: [purchase1, purchase2, purchase3]) - - // When - let receipt = InAppReceipt(payload: receiptPayload) - - // Then - XCTAssertNil(receipt.activeAutoRenewableSubscriptionPurchases(ofProductIdentifier: "test-product-identifier", forDate: String("2017-02-01T07:03:15Z").dateFromISO8601!)) - XCTAssertNotNil(receipt.activeAutoRenewableSubscriptionPurchases(ofProductIdentifier: "test-product-identifier", forDate: String("2017-02-01T07:03:16Z").dateFromISO8601!)) - XCTAssertNotNil(receipt.activeAutoRenewableSubscriptionPurchases(ofProductIdentifier: "test-product-identifier", forDate: String("2017-02-01T07:04:16Z").dateFromISO8601!)) - XCTAssertNotNil(receipt.activeAutoRenewableSubscriptionPurchases(ofProductIdentifier: "test-product-identifier", forDate: String("2017-02-01T07:06:15Z").dateFromISO8601!)) - XCTAssertNil(receipt.activeAutoRenewableSubscriptionPurchases(ofProductIdentifier: "test-product-identifier", forDate: String("2017-02-01T07:06:16Z").dateFromISO8601!)) - XCTAssertNil(receipt.activeAutoRenewableSubscriptionPurchases(ofProductIdentifier: "test-product-identifier", forDate: String("2017-02-01T07:06:17Z").dateFromISO8601!)) - XCTAssertNotNil(receipt.activeAutoRenewableSubscriptionPurchases(ofProductIdentifier: "test-product-identifier", forDate: String("2017-02-01T21:27:11Z").dateFromISO8601!)) - XCTAssertNotNil(receipt.activeAutoRenewableSubscriptionPurchases(ofProductIdentifier: "test-product-identifier", forDate: String("2017-02-01T21:30:11Z").dateFromISO8601!)) - XCTAssertNil(receipt.activeAutoRenewableSubscriptionPurchases(ofProductIdentifier: "test-product-identifier", forDate: String("2017-02-01T21:32:11Z").dateFromISO8601!)) - - } - - func testEmptyAutoRenewableSubscriptionExpirationDate() + func testNoOpenssl() { + //self.measure + //{ + let p = try! PKCS7WrapperMock() + let receipt = InAppReceipt(pkcs7: p, payload: InAppReceiptPayload(noOpenSslData: p.extractASN1Data())) - // Given - let purchase1 = InAppPurchase(webOrderLineItemID: 1, originalPurchaseDateString: "2017-02-01T07:03:18Z", purchaseDateString: "2017-02-01T07:03:16Z", subscriptionExpirationDateString: "", cancellationDateString: "") +// let mock = try! PKCS7WrapperMock() +// mock.extractASN1Data().enumerateASN1AttributesNoOpenssl(withBlock: { (item) in +// +// }) - XCTAssertNil(purchase1.subscriptionExpirationDate) + //} } - func testActiveAutoRenewableSubscriptionPurchasesWithCancellation() { - - // Given - let purchase1 = InAppPurchase(webOrderLineItemID: 1, originalPurchaseDateString: "2017-02-01T07:03:18Z", purchaseDateString: "2017-02-01T07:03:16Z", subscriptionExpirationDateString: "2017-02-01T07:06:16Z", cancellationDateString: "") - let purchase2 = InAppPurchase(webOrderLineItemID: 2, originalPurchaseDateString: "2017-02-01T21:26:12Z", purchaseDateString: "2017-02-01T21:26:11Z", subscriptionExpirationDateString: "2017-02-01T21:29:11Z", cancellationDateString: "2017-02-01T21:27:11Z") - let purchase3 = InAppPurchase(webOrderLineItemID: 3, originalPurchaseDateString: "2017-02-01T21:28:41Z", purchaseDateString: "2017-02-01T21:29:11Z", subscriptionExpirationDateString: "2017-02-01T21:32:11Z", cancellationDateString: "") - let receiptPayload: InAppReceiptPayload = InAppReceiptPayload(purchases: [purchase1, purchase2, purchase3]) - - // When - let receipt = InAppReceipt(payload: receiptPayload) - - // Then - XCTAssertNotNil(receipt.activeAutoRenewableSubscriptionPurchases(ofProductIdentifier: "test-product-identifier", forDate: String("2017-02-01T07:04:16Z").dateFromISO8601!)) - XCTAssertNil(receipt.activeAutoRenewableSubscriptionPurchases(ofProductIdentifier: "test-product-identifier", forDate: String("2017-02-01T21:28:11Z").dateFromISO8601!)) - XCTAssertNotNil(receipt.activeAutoRenewableSubscriptionPurchases(ofProductIdentifier: "test-product-identifier", forDate: String("2017-02-01T21:30:11Z").dateFromISO8601!)) - - } - - func testActiveAutoRenewableSubscriptionPurchasesWhenProductIdentifierDoesNotMatch() { - - // Given - let purchase1 = InAppPurchase(webOrderLineItemID: 1, originalPurchaseDateString: "2017-02-01T07:03:18Z", purchaseDateString: "2017-02-01T07:03:16Z", subscriptionExpirationDateString: "2017-02-01T07:06:16Z", cancellationDateString: "") - let receiptPayload: InAppReceiptPayload = InAppReceiptPayload(purchases: [purchase1]) - - // When - let receipt = InAppReceipt(payload: receiptPayload) - - // Then - XCTAssertNil(receipt.activeAutoRenewableSubscriptionPurchases(ofProductIdentifier: "test-product-identifier-does-not-match", forDate: String("2017-02-01T07:04:16Z").dateFromISO8601!)) - - } - - func testHasActiveAutoRenewableSubscription() { - - // Given - let purchase1 = InAppPurchase(webOrderLineItemID: 1, originalPurchaseDateString: "2017-02-01T07:03:18Z", purchaseDateString: "2017-02-01T07:03:16Z", subscriptionExpirationDateString: "2017-02-01T07:06:16Z", cancellationDateString: "") - let receiptPayload: InAppReceiptPayload = InAppReceiptPayload(purchases: [purchase1]) - - // When - let receipt = InAppReceipt(payload: receiptPayload) - - // Then - XCTAssertFalse(receipt.hasActiveAutoRenewableSubscription(ofProductIdentifier: "test-product-identifier", forDate: String("2017-02-01T07:03:15Z").dateFromISO8601!)) - XCTAssertTrue(receipt.hasActiveAutoRenewableSubscription(ofProductIdentifier: "test-product-identifier", forDate: String("2017-02-01T07:03:16Z").dateFromISO8601!)) + func test() + { +// self.measure +// { + let p = try! PKCS7WrapperMock() + let receipt = InAppReceipt(pkcs7: p, payload: InAppReceiptPayload(asn1Data: p.extractASN1Data())) +// } } + +// func testActiveAutoRenewableSubscriptionPurchasesWithoutCancellation() { +// +// // Given +// let purchase1 = InAppPurchase(webOrderLineItemID: 1, originalPurchaseDateString: "2017-02-01T07:03:18Z", purchaseDateString: "2017-02-01T07:03:16Z", subscriptionExpirationDateString: "2017-02-01T07:06:16Z", cancellationDateString: "") +// let purchase2 = InAppPurchase(webOrderLineItemID: 2, originalPurchaseDateString: "2017-02-01T21:26:12Z", purchaseDateString: "2017-02-01T21:26:11Z", subscriptionExpirationDateString: "2017-02-01T21:29:11Z", cancellationDateString: "") +// let purchase3 = InAppPurchase(webOrderLineItemID: 3, originalPurchaseDateString: "2017-02-01T21:28:41Z", purchaseDateString: "2017-02-01T21:29:11Z", subscriptionExpirationDateString: "2017-02-01T21:32:11Z", cancellationDateString: "") +// let receiptPayload: InAppReceiptPayload = InAppReceiptPayload(purchases: [purchase1, purchase2, purchase3]) +// +// // When +// let receipt = InAppReceipt(pkcs7: try! PKCS7WrapperMock()) +// +// // Then +// XCTAssertNil(receipt.activeAutoRenewableSubscriptionPurchases(ofProductIdentifier: "test-product-identifier", forDate: String("2017-02-01T07:03:15Z").dateFromISO8601!)) +// XCTAssertNotNil(receipt.activeAutoRenewableSubscriptionPurchases(ofProductIdentifier: "test-product-identifier", forDate: String("2017-02-01T07:03:16Z").dateFromISO8601!)) +// XCTAssertNotNil(receipt.activeAutoRenewableSubscriptionPurchases(ofProductIdentifier: "test-product-identifier", forDate: String("2017-02-01T07:04:16Z").dateFromISO8601!)) +// XCTAssertNotNil(receipt.activeAutoRenewableSubscriptionPurchases(ofProductIdentifier: "test-product-identifier", forDate: String("2017-02-01T07:06:15Z").dateFromISO8601!)) +// XCTAssertNil(receipt.activeAutoRenewableSubscriptionPurchases(ofProductIdentifier: "test-product-identifier", forDate: String("2017-02-01T07:06:16Z").dateFromISO8601!)) +// XCTAssertNil(receipt.activeAutoRenewableSubscriptionPurchases(ofProductIdentifier: "test-product-identifier", forDate: String("2017-02-01T07:06:17Z").dateFromISO8601!)) +// XCTAssertNotNil(receipt.activeAutoRenewableSubscriptionPurchases(ofProductIdentifier: "test-product-identifier", forDate: String("2017-02-01T21:27:11Z").dateFromISO8601!)) +// XCTAssertNotNil(receipt.activeAutoRenewableSubscriptionPurchases(ofProductIdentifier: "test-product-identifier", forDate: String("2017-02-01T21:30:11Z").dateFromISO8601!)) +// XCTAssertNil(receipt.activeAutoRenewableSubscriptionPurchases(ofProductIdentifier: "test-product-identifier", forDate: String("2017-02-01T21:32:11Z").dateFromISO8601!)) +// +// } +// +// func testEmptyAutoRenewableSubscriptionExpirationDate() +// { +// +// // Given +// let purchase1 = InAppPurchase(webOrderLineItemID: 1, originalPurchaseDateString: "2017-02-01T07:03:18Z", purchaseDateString: "2017-02-01T07:03:16Z", subscriptionExpirationDateString: "", cancellationDateString: "") +// +// XCTAssertNil(purchase1.subscriptionExpirationDate) +// } +// +// func testActiveAutoRenewableSubscriptionPurchasesWithCancellation() { +// +// // Given +// let purchase1 = InAppPurchase(webOrderLineItemID: 1, originalPurchaseDateString: "2017-02-01T07:03:18Z", purchaseDateString: "2017-02-01T07:03:16Z", subscriptionExpirationDateString: "2017-02-01T07:06:16Z", cancellationDateString: "") +// let purchase2 = InAppPurchase(webOrderLineItemID: 2, originalPurchaseDateString: "2017-02-01T21:26:12Z", purchaseDateString: "2017-02-01T21:26:11Z", subscriptionExpirationDateString: "2017-02-01T21:29:11Z", cancellationDateString: "2017-02-01T21:27:11Z") +// let purchase3 = InAppPurchase(webOrderLineItemID: 3, originalPurchaseDateString: "2017-02-01T21:28:41Z", purchaseDateString: "2017-02-01T21:29:11Z", subscriptionExpirationDateString: "2017-02-01T21:32:11Z", cancellationDateString: "") +// let receiptPayload: InAppReceiptPayload = InAppReceiptPayload(purchases: [purchase1, purchase2, purchase3]) +// +// // When +// let receipt = InAppReceipt(payload: receiptPayload) +// +// // Then +// XCTAssertNotNil(receipt.activeAutoRenewableSubscriptionPurchases(ofProductIdentifier: "test-product-identifier", forDate: String("2017-02-01T07:04:16Z").dateFromISO8601!)) +// XCTAssertNil(receipt.activeAutoRenewableSubscriptionPurchases(ofProductIdentifier: "test-product-identifier", forDate: String("2017-02-01T21:28:11Z").dateFromISO8601!)) +// XCTAssertNotNil(receipt.activeAutoRenewableSubscriptionPurchases(ofProductIdentifier: "test-product-identifier", forDate: String("2017-02-01T21:30:11Z").dateFromISO8601!)) +// +// } +// +// func testActiveAutoRenewableSubscriptionPurchasesWhenProductIdentifierDoesNotMatch() { +// +// // Given +// let purchase1 = InAppPurchase(webOrderLineItemID: 1, originalPurchaseDateString: "2017-02-01T07:03:18Z", purchaseDateString: "2017-02-01T07:03:16Z", subscriptionExpirationDateString: "2017-02-01T07:06:16Z", cancellationDateString: "") +// let receiptPayload: InAppReceiptPayload = InAppReceiptPayload(purchases: [purchase1]) +// +// // When +// let receipt = InAppReceipt(payload: receiptPayload) +// +// // Then +// XCTAssertNil(receipt.activeAutoRenewableSubscriptionPurchases(ofProductIdentifier: "test-product-identifier-does-not-match", forDate: String("2017-02-01T07:04:16Z").dateFromISO8601!)) +// +// } +// +// func testHasActiveAutoRenewableSubscription() { +// +// // Given +// let purchase1 = InAppPurchase(webOrderLineItemID: 1, originalPurchaseDateString: "2017-02-01T07:03:18Z", purchaseDateString: "2017-02-01T07:03:16Z", subscriptionExpirationDateString: "2017-02-01T07:06:16Z", cancellationDateString: "") +// let receiptPayload: InAppReceiptPayload = InAppReceiptPayload(purchases: [purchase1]) +// +// // When +// let receipt = InAppReceipt(payload: receiptPayload) +// +// // Then +// XCTAssertFalse(receipt.hasActiveAutoRenewableSubscription(ofProductIdentifier: "test-product-identifier", forDate: String("2017-02-01T07:03:15Z").dateFromISO8601!)) +// XCTAssertTrue(receipt.hasActiveAutoRenewableSubscription(ofProductIdentifier: "test-product-identifier", forDate: String("2017-02-01T07:03:16Z").dateFromISO8601!)) +// +// } } @@ -95,6 +120,8 @@ fileprivate extension InAppPurchase { init(webOrderLineItemID: Int, originalPurchaseDateString: String, purchaseDateString: String, subscriptionExpirationDateString: String, cancellationDateString: String) { + self.init(asn1Data: Data()) + self.productIdentifier = "test-product-identifier" self.transactionIdentifier = "test-transaction-identifier" self.originalTransactionIdentifier = originalPurchaseDateString @@ -104,6 +131,8 @@ fileprivate extension InAppPurchase self.cancellationDateString = cancellationDateString self.webOrderLineItemID = webOrderLineItemID self.quantity = 1 + + } } @@ -111,8 +140,7 @@ fileprivate extension InAppReceipt { init(payload: InAppReceiptPayload) { - self.payload = payload - self.pkcs7Container = try! PKCS7WrapperMock() + self.init(pkcs7: try! PKCS7WrapperMock(), payload: payload) } } @@ -120,14 +148,7 @@ fileprivate extension InAppReceiptPayload { init(purchases: [InAppPurchase]) { - self.purchases = purchases - self.bundleIdentifier = "test-bundle-identifier" - self.appVersion = "" - self.originalAppVersion = "" - self.expirationDate = "" - self.bundleIdentifierData = Data() - self.opaqueValue = Data() - self.receiptHash = Data() + self.init(bundleIdentifier: "test-bundle-identifier", appVersion: "", originalAppVersion: "", purchases: purchases, expirationDate: "", bundleIdentifierData: Data(), opaqueValue: Data(), receiptHash: Data(), receiptCreationDate: "") } } @@ -136,7 +157,7 @@ fileprivate class PKCS7WrapperMock: PKCS7Wrapper { init() throws { - try super.init(receipt: Data(base64Encoded: "MCcGCSqGSIb3DQEHAqAaMBgCAQExADALBgkqhkiG9w0BBwGgAKEAMQA=")!) + try super.init(receipt: Data(base64Encoded: receiptString64)!) } } @@ -166,3 +187,15 @@ fileprivate extension String return Date.iso8601Formatter.date(from: self) } } + + + + + + + + + + + +let receiptString64: String = "MIIfQQYJKoZIhvcNAQcCoIIfMjCCHy4CAQExCzAJBgUrDgMCGgUAMIIO4gYJKoZIhvcNAQcBoIIO0wSCDs8xgg7LMAoCAQgCAQEEAhYAMAoCARQCAQEEAgwAMAsCAQECAQEEAwIBADALAgELAgEBBAMCAQAwCwIBDwIBAQQDAgEAMAsCARACAQEEAwIBADALAgEZAgEBBAMCAQMwDAIBCgIBAQQEFgI0KzAMAgEOAgEBBAQCAgCNMA0CAQMCAQEEBQwDMS40MA0CAQ0CAQEEBQIDAWDAMA0CARMCAQEEBQwDMS4wMA4CAQkCAQEEBgIEUDI0NzAYAgEEAgECBBABJMBeNxZqWwseuzPYSls4MBsCAQACAQEEEwwRUHJvZHVjdGlvblNhbmRib3gwHAIBBQIBAQQUWAirPZncT5AbaMvvZDi4C95PmFowHgIBDAIBAQQWFhQyMDE2LTA4LTI3VDA2OjA2OjMyWjAeAgESAgEBBBYWFDIwMTMtMDgtMDFUMDc6MDA6MDBaMCACAQICAQEEGAwWY29tLndoYWxlcm9jay5nb2xmd2FuZzA8AgEHAgEBBDTpCdRwFREffToLgPBErAHyO00LFEeZDROXwZALd4+0w5w48GSXTKVLez6V97/DTqyTFwavMFYCAQYCAQEETt6uyihMRqB+an09xn5FRlBj/Tn9So41jSuWKyPNr9+pAGxy5tqk5sWlmeub2Tic0UKGaY8OfDr15i234VQZQLllk2C0liCI5ZeOeWxvxDCCAWgCARECAQEEggFeMYIBWjALAgIGrQIBAQQCDAAwCwICBrACAQEEAhYAMAsCAgayAgEBBAIMADALAgIGswIBAQQCDAAwCwICBrQCAQEEAgwAMAsCAga1AgEBBAIMADALAgIGtgIBAQQCDAAwDAICBqUCAQEEAwIBATAMAgIGqwIBAQQDAgEDMAwCAgauAgEBBAMCAQAwDAICBrECAQEEAwIBADASAgIGrwIBAQQJAgcDjX6mv/A4MBQCAgamAgEBBAsMCUdXTU9OVEhMWTAbAgIGpwIBAQQSDBAxMDAwMDAwMjMyMjUzMDQzMBsCAgapAgEBBBIMEDEwMDAwMDAyMzIyNTMwMjIwHwICBqgCAQEEFhYUMjAxNi0wOC0yN1QwMToyNzozMVowHwICBqoCAQEEFhYUMjAxNi0wOC0yN1QwMToyNzoxMVowHwICBqwCAQEEFhYUMjAxNi0wOC0yN1QwMTozMjozMVowggFoAgERAgEBBIIBXjGCAVowCwICBq0CAQEEAgwAMAsCAgawAgEBBAIWADALAgIGsgIBAQQCDAAwCwICBrMCAQEEAgwAMAsCAga0AgEBBAIMADALAgIGtQIBAQQCDAAwCwICBrYCAQEEAgwAMAwCAgalAgEBBAMCAQEwDAICBqsCAQEEAwIBAzAMAgIGrgIBAQQDAgEAMAwCAgaxAgEBBAMCAQAwEgICBq8CAQEECQIHA41+pr/wOjAUAgIGpgIBAQQLDAlHV01PTlRITFkwGwICBqcCAQEEEgwQMTAwMDAwMDIzMjI1MzE0NDAbAgIGqQIBAQQSDBAxMDAwMDAwMjMyMjUzMDIyMB8CAgaoAgEBBBYWFDIwMTYtMDgtMjdUMDE6MzM6MDlaMB8CAgaqAgEBBBYWFDIwMTYtMDgtMjdUMDE6MzM6MTBaMB8CAgasAgEBBBYWFDIwMTYtMDgtMjdUMDE6Mzg6MDlaMIIBaAIBEQIBAQSCAV4xggFaMAsCAgatAgEBBAIMADALAgIGsAIBAQQCFgAwCwICBrICAQEEAgwAMAsCAgazAgEBBAIMADALAgIGtAIBAQQCDAAwCwICBrUCAQEEAgwAMAsCAga2AgEBBAIMADAMAgIGpQIBAQQDAgEBMAwCAgarAgEBBAMCAQMwDAICBq4CAQEEAwIBADAMAgIGsQIBAQQDAgEAMBICAgavAgEBBAkCBwONfqa/8EIwFAICBqYCAQEECwwJR1dNT05USExZMBsCAganAgEBBBIMEDEwMDAwMDAyMzIyNTM0NDgwGwICBqkCAQEEEgwQMTAwMDAwMDIzMjI1MzAyMjAfAgIGqAIBAQQWFhQyMDE2LTA4LTI3VDAxOjM4OjU5WjAfAgIGqgIBAQQWFhQyMDE2LTA4LTI3VDAxOjM4OjU5WjAfAgIGrAIBAQQWFhQyMDE2LTA4LTI3VDAxOjQzOjU5WjCCAWgCARECAQEEggFeMYIBWjALAgIGrQIBAQQCDAAwCwICBrACAQEEAhYAMAsCAgayAgEBBAIMADALAgIGswIBAQQCDAAwCwICBrQCAQEEAgwAMAsCAga1AgEBBAIMADALAgIGtgIBAQQCDAAwDAICBqUCAQEEAwIBATAMAgIGqwIBAQQDAgEDMAwCAgauAgEBBAMCAQAwDAICBrECAQEEAwIBADASAgIGrwIBAQQJAgcDjX6mv/BLMBQCAgamAgEBBAsMCUdXTU9OVEhMWTAbAgIGpwIBAQQSDBAxMDAwMDAwMjMyMjUzNTY5MBsCAgapAgEBBBIMEDEwMDAwMDAyMzIyNTMwMjIwHwICBqgCAQEEFhYUMjAxNi0wOC0yN1QwMTo0Mzo1OVowHwICBqoCAQEEFhYUMjAxNi0wOC0yN1QwMTo0MzozNVowHwICBqwCAQEEFhYUMjAxNi0wOC0yN1QwMTo0ODo1OVowggFoAgERAgEBBIIBXjGCAVowCwICBq0CAQEEAgwAMAsCAgawAgEBBAIWADALAgIGsgIBAQQCDAAwCwICBrMCAQEEAgwAMAsCAga0AgEBBAIMADALAgIGtQIBAQQCDAAwCwICBrYCAQEEAgwAMAwCAgalAgEBBAMCAQEwDAICBqsCAQEEAwIBAzAMAgIGrgIBAQQDAgEAMAwCAgaxAgEBBAMCAQAwEgICBq8CAQEECQIHA41+pr/wVTAUAgIGpgIBAQQLDAlHV01PTlRITFkwGwICBqcCAQEEEgwQMTAwMDAwMDIzMjI1NDA0NDAbAgIGqQIBAQQSDBAxMDAwMDAwMjMyMjUzMDIyMB8CAgaoAgEBBBYWFDIwMTYtMDgtMjdUMDE6NDg6NTlaMB8CAgaqAgEBBBYWFDIwMTYtMDgtMjdUMDE6NDg6MjBaMB8CAgasAgEBBBYWFDIwMTYtMDgtMjdUMDE6NTM6NTlaMIIBaAIBEQIBAQSCAV4xggFaMAsCAgatAgEBBAIMADALAgIGsAIBAQQCFgAwCwICBrICAQEEAgwAMAsCAgazAgEBBAIMADALAgIGtAIBAQQCDAAwCwICBrUCAQEEAgwAMAsCAga2AgEBBAIMADAMAgIGpQIBAQQDAgEBMAwCAgarAgEBBAMCAQMwDAICBq4CAQEEAwIBADAMAgIGsQIBAQQDAgEAMBICAgavAgEBBAkCBwONfqa/8F4wFAICBqYCAQEECwwJR1dNT05USExZMBsCAganAgEBBBIMEDEwMDAwMDAyMzIyNTQzNTYwGwICBqkCAQEEEgwQMTAwMDAwMDIzMjI1MzAyMjAfAgIGqAIBAQQWFhQyMDE2LTA4LTI3VDAxOjU4OjE4WjAfAgIGqgIBAQQWFhQyMDE2LTA4LTI3VDAxOjU4OjE5WjAfAgIGrAIBAQQWFhQyMDE2LTA4LTI3VDAyOjAzOjE4WjCCAWgCARECAQEEggFeMYIBWjALAgIGrQIBAQQCDAAwCwICBrACAQEEAhYAMAsCAgayAgEBBAIMADALAgIGswIBAQQCDAAwCwICBrQCAQEEAgwAMAsCAga1AgEBBAIMADALAgIGtgIBAQQCDAAwDAICBqUCAQEEAwIBATAMAgIGqwIBAQQDAgEDMAwCAgauAgEBBAMCAQAwDAICBrECAQEEAwIBADASAgIGrwIBAQQJAgcDjX6mv/ByMBQCAgamAgEBBAsMCUdXTU9OVEhMWTAbAgIGpwIBAQQSDBAxMDAwMDAwMjMyMjY3NTY4MBsCAgapAgEBBBIMEDEwMDAwMDAyMzIyNTMwMjIwHwICBqgCAQEEFhYUMjAxNi0wOC0yN1QwNTo1OTozNFowHwICBqoCAQEEFhYUMjAxNi0wOC0yN1QwNTo1OTozNVowHwICBqwCAQEEFhYUMjAxNi0wOC0yN1QwNjowNDozNFowggFoAgERAgEBBIIBXjGCAVowCwICBq0CAQEEAgwAMAsCAgawAgEBBAIWADALAgIGsgIBAQQCDAAwCwICBrMCAQEEAgwAMAsCAga0AgEBBAIMADALAgIGtQIBAQQCDAAwCwICBrYCAQEEAgwAMAwCAgalAgEBBAMCAQEwDAICBqsCAQEEAwIBAzAMAgIGrgIBAQQDAgEAMAwCAgaxAgEBBAMCAQAwEgICBq8CAQEECQIHA41+pr/xmTAUAgIGpgIBAQQLDAlHV01PTlRITFkwGwICBqcCAQEEEgwQMTAwMDAwMDIzMjI2Nzg5NzAbAgIGqQIBAQQSDBAxMDAwMDAwMjMyMjUzMDIyMB8CAgaoAgEBBBYWFDIwMTYtMDgtMjdUMDY6MDQ6MzRaMB8CAgaqAgEBBBYWFDIwMTYtMDgtMjdUMDY6MDM6NDZaMB8CAgasAgEBBBYWFDIwMTYtMDgtMjdUMDY6MDk6MzRaMIIBaAIBEQIBAQSCAV4xggFaMAsCAgatAgEBBAIMADALAgIGsAIBAQQCFgAwCwICBrICAQEEAgwAMAsCAgazAgEBBAIMADALAgIGtAIBAQQCDAAwCwICBrUCAQEEAgwAMAsCAga2AgEBBAIMADAMAgIGpQIBAQQDAgEBMAwCAgarAgEBBAMCAQMwDAICBq4CAQEEAwIBADAMAgIGsQIBAQQDAgEBMBICAgavAgEBBAkCBwONfqa/8DcwFAICBqYCAQEECwwJR1dNT05USExZMBsCAganAgEBBBIMEDEwMDAwMDAyMzIyNTMwMjIwGwICBqkCAQEEEgwQMTAwMDAwMDIzMjI1MzAyMjAfAgIGqAIBAQQWFhQyMDE2LTA4LTI3VDAxOjI0OjMxWjAfAgIGqgIBAQQWFhQyMDE2LTA4LTI3VDAxOjI0OjMyWjAfAgIGrAIBAQQWFhQyMDE2LTA4LTI3VDAxOjI3OjMxWqCCDmUwggV8MIIEZKADAgECAggO61eH554JjTANBgkqhkiG9w0BAQUFADCBljELMAkGA1UEBhMCVVMxEzARBgNVBAoMCkFwcGxlIEluYy4xLDAqBgNVBAsMI0FwcGxlIFdvcmxkd2lkZSBEZXZlbG9wZXIgUmVsYXRpb25zMUQwQgYDVQQDDDtBcHBsZSBXb3JsZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9ucyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNTExMTMwMjE1MDlaFw0yMzAyMDcyMTQ4NDdaMIGJMTcwNQYDVQQDDC5NYWMgQXBwIFN0b3JlIGFuZCBpVHVuZXMgU3RvcmUgUmVjZWlwdCBTaWduaW5nMSwwKgYDVQQLDCNBcHBsZSBXb3JsZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UEBhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQClz4H9JaKBW9aH7SPaMxyO4iPApcQmyz3Gn+xKDVWG/6QC15fKOVRtfX+yVBidxCxScY5ke4LOibpJ1gjltIhxzz9bRi7GxB24A6lYogQ+IXjV27fQjhKNg0xbKmg3k8LyvR7E0qEMSlhSqxLj7d0fmBWQNS3CzBLKjUiB91h4VGvojDE2H0oGDEdU8zeQuLKSiX1fpIVK4cCc4Lqku4KXY/Qrk8H9Pm/KwfU8qY9SGsAlCnYO3v6Z/v/Ca/VbXqxzUUkIVonMQ5DMjoEC0KCXtlyxoWlph5AQaCYmObgdEHOwCl3Fc9DfdjvYLdmIHuPsB8/ijtDT+iZVge/iA0kjAgMBAAGjggHXMIIB0zA/BggrBgEFBQcBAQQzMDEwLwYIKwYBBQUHMAGGI2h0dHA6Ly9vY3NwLmFwcGxlLmNvbS9vY3NwMDMtd3dkcjA0MB0GA1UdDgQWBBSRpJz8xHa3n6CK9E31jzZd7SsEhTAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFIgnFwmpthhgi+zruvZHWcVSVKO3MIIBHgYDVR0gBIIBFTCCAREwggENBgoqhkiG92NkBQYBMIH+MIHDBggrBgEFBQcCAjCBtgyBs1JlbGlhbmNlIG9uIHRoaXMgY2VydGlmaWNhdGUgYnkgYW55IHBhcnR5IGFzc3VtZXMgYWNjZXB0YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5kYXJkIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHVzZSwgY2VydGlmaWNhdGUgcG9saWN5IGFuZCBjZXJ0aWZpY2F0aW9uIHByYWN0aWNlIHN0YXRlbWVudHMuMDYGCCsGAQUFBwIBFipodHRwOi8vd3d3LmFwcGxlLmNvbS9jZXJ0aWZpY2F0ZWF1dGhvcml0eS8wDgYDVR0PAQH/BAQDAgeAMBAGCiqGSIb3Y2QGCwEEAgUAMA0GCSqGSIb3DQEBBQUAA4IBAQANphvTLj3jWysHbkKWbNPojEMwgl/gXNGNvr0PvRr8JZLbjIXDgFnf4+LXLgUUrA3btrj+/DUufMutF2uOfx/kd7mxZ5W0E16mGYZ2+FogledjjA9z/Ojtxh+umfhlSFyg4Cg6wBA3LbmgBDkfc7nIBf3y3n8aKipuKwH8oCBc2et9J6Yz+PWY4L5E27FMZ/xuCk/J4gao0pfzp45rUaJahHVl0RYEYuPBX/UIqc9o2ZIAycGMs/iNAGS6WGDAfK+PdcppuVsq1h1obphC9UynNxmbzDscehlD86Ntv0hgBgw2kivs3hi1EdotI9CO/KBpnBcbnoB7OUdFMGEvxxOoMIIEIjCCAwqgAwIBAgIIAd68xDltoBAwDQYJKoZIhvcNAQEFBQAwYjELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkFwcGxlIEluYy4xJjAkBgNVBAsTHUFwcGxlIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRYwFAYDVQQDEw1BcHBsZSBSb290IENBMB4XDTEzMDIwNzIxNDg0N1oXDTIzMDIwNzIxNDg0N1owgZYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3JsZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3aWRlIERldmVsb3BlciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDKOFSmy1aqyCQ5SOmM7uxfuH8mkbw0U3rOfGOAYXdkXqUHI7Y5/lAtFVZYcC1+xG7BSoU+L/DehBqhV8mvexj/avoVEkkVCBmsqtsqMu2WY2hSFT2Miuy/axiV4AOsAX2XBWfODoWVN2rtCbauZ81RZJ/GXNG8V25nNYB2NqSHgW44j9grFU57Jdhav06DwY3Sk9UacbVgnJ0zTlX5ElgMhrgWDcHld0WNUEi6Ky3klIXh6MSdxmilsKP8Z35wugJZS3dCkTm59c3hTO/AO0iMpuUhXf1qarunFjVg0uat80YpyejDi+l5wGphZxWy8P3laLxiX27Pmd3vG2P+kmWrAgMBAAGjgaYwgaMwHQYDVR0OBBYEFIgnFwmpthhgi+zruvZHWcVSVKO3MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUK9BpR5R2Cf70a40uQKb3R01/CF4wLgYDVR0fBCcwJTAjoCGgH4YdaHR0cDovL2NybC5hcHBsZS5jb20vcm9vdC5jcmwwDgYDVR0PAQH/BAQDAgGGMBAGCiqGSIb3Y2QGAgEEAgUAMA0GCSqGSIb3DQEBBQUAA4IBAQBPz+9Zviz1smwvj+4ThzLoBTWobot9yWkMudkXvHcs1Gfi/ZptOllc34MBvbKuKmFysa/Nw0Uwj6ODDc4dR7Txk4qjdJukw5hyhzs+r0ULklS5MruQGFNrCk4QttkdUGwhgAqJTleMa1s8Pab93vcNIx0LSiaHP7qRkkykGRIZbVf1eliHe2iK5IaMSuviSRSqpd1VAKmuu0swruGgsbwpgOYJd+W+NKIByn/c4grmO7i77LpilfMFY0GCzQ87HUyVpNur+cmV6U/kTecmmYHpvPm0KdIBembhLoz2IYrF+Hjhga6/05Cdqa3zr/04GpZnMBxRpVzscYqCtGwPDBUfMIIEuzCCA6OgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQXBwbGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxFjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwHhcNMDYwNDI1MjE0MDM2WhcNMzUwMjA5MjE0MDM2WjBiMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQXBwbGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxFjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkkakJH5HbHkdQ6wXtXnmELes2oldMVeyLGYne+Uts9QerIjAC6Bg++FAJ039BqJj50cpmnCRrEdCju+QbKsMflZ56DKRHi1vUFjczy8QPTc4UadHJGXL1XQ7Vf1+b8iUDulWPTV0N8WQ1IxVLFVkds5T39pyez1C6wVhQZ48ItCD3y6wsIG9wtj8BMIy3Q88PnT3zK0koGsj+zrW5DtleHNbLPbU6rfQPDgCSC7EhFi501TwN22IWq6NxkkdTVcGvL0Gz+PvjcM3mo0xFfh9Ma1CWQYnEdGILEINBhzOKgbEwWOxaBDKMaLOPHd5lc/9nXmW8Sdh2nzMUZaF3lMktAgMBAAGjggF6MIIBdjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUK9BpR5R2Cf70a40uQKb3R01/CF4wHwYDVR0jBBgwFoAUK9BpR5R2Cf70a40uQKb3R01/CF4wggERBgNVHSAEggEIMIIBBDCCAQAGCSqGSIb3Y2QFATCB8jAqBggrBgEFBQcCARYeaHR0cHM6Ly93d3cuYXBwbGUuY29tL2FwcGxlY2EvMIHDBggrBgEFBQcCAjCBthqBs1JlbGlhbmNlIG9uIHRoaXMgY2VydGlmaWNhdGUgYnkgYW55IHBhcnR5IGFzc3VtZXMgYWNjZXB0YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5kYXJkIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHVzZSwgY2VydGlmaWNhdGUgcG9saWN5IGFuZCBjZXJ0aWZpY2F0aW9uIHByYWN0aWNlIHN0YXRlbWVudHMuMA0GCSqGSIb3DQEBBQUAA4IBAQBcNplMLXi37Yyb3PN3m/J20ncwT8EfhYOFG5k9RzfyqZtAjizUsZAS2L70c5vu0mQPy3lPNNiiPvl4/2vIB+x9OYOLUyDTOMSxv5pPCmv/K/xZpwUJfBdAVhEedNO3iyM7R6PVbyTi69G3cN8PReEnyvFteO3ntRcXqNx+IjXKJdXZD9Zr1KIkIxH3oayPc4FgxhtbCS+SsvhESPBgOJ4V9T0mZyCKM2r3DYLP3uujL/lTaltkwGMzd/c6ByxW69oPIQ7aunMZT7XZNn/Bh1XZp5m5MkL72NVxnn6hUrcbvZNCJBIqxw8dtk2cXmPIS4AXUKqK1drk/NAJBzewdXUhMYIByzCCAccCAQEwgaMwgZYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3JsZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3aWRlIERldmVsb3BlciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkCCA7rV4fnngmNMAkGBSsOAwIaBQAwDQYJKoZIhvcNAQEBBQAEggEAHdsohKnluYqS9c7K8o0KEAGgB9X4dSufEYbPf7qUHWQAtl1tkJQcxSM6I5FB6G5Zz5G4/zex1T17UTZ4dOad8tuIICp5Mb9XOtO6ScJOmpbTJPvG9nObAbgr8QuHKtlpUDvb6/UsYfVpjYVSJbg0xYwjk0E4tPHurfnGygAbHrlNc/Dt7yUFjVUxXzzMZkdtlqhGVyxtR6wAEEzN7xaQbrFI4fplw8mnPBHuKVrKRh2QWUCJq3G5A+sZ3aYaskttaCK6WoHuSTvJXLZlf4TfUt63N6Sq5S0fFcJsT45vkloZFxrCfkJjnQJ2KUuG4nwcwz09L4g953ci90mFH5e3TQ==" diff --git a/Vendor/OpenSSL/module.modulemap b/Vendor/OpenSSL/module.modulemap index 982d694..eab6652 100644 --- a/Vendor/OpenSSL/module.modulemap +++ b/Vendor/OpenSSL/module.modulemap @@ -4,5 +4,6 @@ module openssl [system][extern_c] header "include/openssl/pkcs7.h" header "include/openssl/objects.h" header "include/openssl/x509.h" + header "include/openssl/e_os2.h" export * } diff --git a/Vendor/asn1/include/BIT_STRING.c b/Vendor/asn1/include/BIT_STRING.c new file mode 100644 index 0000000..0cff770 --- /dev/null +++ b/Vendor/asn1/include/BIT_STRING.c @@ -0,0 +1,652 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include + +/* + * BIT STRING basic type description. + */ +static const ber_tlv_tag_t asn_DEF_BIT_STRING_tags[] = { + (ASN_TAG_CLASS_UNIVERSAL | (3 << 2)) +}; +asn_OCTET_STRING_specifics_t asn_SPC_BIT_STRING_specs = { + sizeof(BIT_STRING_t), + offsetof(BIT_STRING_t, _asn_ctx), + ASN_OSUBV_BIT +}; +asn_TYPE_operation_t asn_OP_BIT_STRING = { + OCTET_STRING_free, /* Implemented in terms of OCTET STRING */ + BIT_STRING_print, + BIT_STRING_compare, + OCTET_STRING_decode_ber, /* Implemented in terms of OCTET STRING */ + OCTET_STRING_encode_der, /* Implemented in terms of OCTET STRING */ + OCTET_STRING_decode_xer_binary, + BIT_STRING_encode_xer, +#ifdef ASN_DISABLE_OER_SUPPORT + 0, + 0, +#else + BIT_STRING_decode_oer, + BIT_STRING_encode_oer, +#endif /* ASN_DISABLE_OER_SUPPORT */ +#ifdef ASN_DISABLE_PER_SUPPORT + 0, + 0, +#else + BIT_STRING_decode_uper, /* Unaligned PER decoder */ + BIT_STRING_encode_uper, /* Unaligned PER encoder */ +#endif /* ASN_DISABLE_PER_SUPPORT */ + BIT_STRING_random_fill, + 0 /* Use generic outmost tag fetcher */ +}; +asn_TYPE_descriptor_t asn_DEF_BIT_STRING = { + "BIT STRING", + "BIT_STRING", + &asn_OP_BIT_STRING, + asn_DEF_BIT_STRING_tags, + sizeof(asn_DEF_BIT_STRING_tags) + / sizeof(asn_DEF_BIT_STRING_tags[0]), + asn_DEF_BIT_STRING_tags, /* Same as above */ + sizeof(asn_DEF_BIT_STRING_tags) + / sizeof(asn_DEF_BIT_STRING_tags[0]), + { 0, 0, BIT_STRING_constraint }, + 0, 0, /* No members */ + &asn_SPC_BIT_STRING_specs +}; + +/* + * BIT STRING generic constraint. + */ +int +BIT_STRING_constraint(const asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + + if(st && st->buf) { + if((st->size == 0 && st->bits_unused) + || st->bits_unused < 0 || st->bits_unused > 7) { + ASN__CTFAIL(app_key, td, sptr, + "%s: invalid padding byte (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + } else { + ASN__CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + return 0; +} + +static const char *_bit_pattern[16] = { + "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", + "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111" +}; + +asn_enc_rval_t +BIT_STRING_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_enc_rval_t er; + char scratch[128]; + char *p = scratch; + char *scend = scratch + (sizeof(scratch) - 10); + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + int xcan = (flags & XER_F_CANONICAL); + uint8_t *buf; + uint8_t *end; + + if(!st || !st->buf) + ASN__ENCODE_FAILED; + + er.encoded = 0; + + buf = st->buf; + end = buf + st->size - 1; /* Last byte is special */ + + /* + * Binary dump + */ + for(; buf < end; buf++) { + int v = *buf; + int nline = xcan?0:(((buf - st->buf) % 8) == 0); + if(p >= scend || nline) { + ASN__CALLBACK(scratch, p - scratch); + p = scratch; + if(nline) ASN__TEXT_INDENT(1, ilevel); + } + memcpy(p + 0, _bit_pattern[v >> 4], 4); + memcpy(p + 4, _bit_pattern[v & 0x0f], 4); + p += 8; + } + + if(!xcan && ((buf - st->buf) % 8) == 0) + ASN__TEXT_INDENT(1, ilevel); + ASN__CALLBACK(scratch, p - scratch); + p = scratch; + + if(buf == end) { + int v = *buf; + int ubits = st->bits_unused; + int i; + for(i = 7; i >= ubits; i--) + *p++ = (v & (1 << i)) ? 0x31 : 0x30; + ASN__CALLBACK(scratch, p - scratch); + } + + if(!xcan) ASN__TEXT_INDENT(1, ilevel - 1); + + ASN__ENCODED_OK(er); +cb_failed: + ASN__ENCODE_FAILED; +} + + +/* + * BIT STRING specific contents printer. + */ +int +BIT_STRING_print(const asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, + asn_app_consume_bytes_f *cb, void *app_key) { + const char * const h2c = "0123456789ABCDEF"; + char scratch[64]; + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + uint8_t *buf; + uint8_t *end; + char *p = scratch; + + (void)td; /* Unused argument */ + + if(!st || !st->buf) + return (cb("", 8, app_key) < 0) ? -1 : 0; + + ilevel++; + buf = st->buf; + end = buf + st->size; + + /* + * Hexadecimal dump. + */ + for(; buf < end; buf++) { + if((buf - st->buf) % 16 == 0 && (st->size > 16) + && buf != st->buf) { + _i_INDENT(1); + /* Dump the string */ + if(cb(scratch, p - scratch, app_key) < 0) return -1; + p = scratch; + } + *p++ = h2c[*buf >> 4]; + *p++ = h2c[*buf & 0x0F]; + *p++ = 0x20; + } + + if(p > scratch) { + p--; /* Eat the tailing space */ + + if((st->size > 16)) { + _i_INDENT(1); + } + + /* Dump the incomplete 16-bytes row */ + if(cb(scratch, p - scratch, app_key) < 0) + return -1; + } + + if(st->bits_unused) { + int ret = snprintf(scratch, sizeof(scratch), " (%d bit%s unused)", + st->bits_unused, st->bits_unused == 1 ? "" : "s"); + assert(ret > 0 && ret < (ssize_t)sizeof(scratch)); + if(ret > 0 && ret < (ssize_t)sizeof(scratch) + && cb(scratch, ret, app_key) < 0) + return -1; + } + + return 0; +} + +/* + * Non-destructively remove the trailing 0-bits from the given bit string. + */ +static const BIT_STRING_t * +BIT_STRING__compactify(const BIT_STRING_t *st, BIT_STRING_t *tmp) { + const uint8_t *b; + union { + const uint8_t *c_buf; + uint8_t *nc_buf; + } unconst; + + if(st->size == 0) { + assert(st->bits_unused == 0); + return st; + } else { + for(b = &st->buf[st->size - 1]; b > st->buf && *b == 0; b--) { + ; + } + /* b points to the last byte which may contain data */ + if(*b) { + int unused = 7; + uint8_t v = *b; + v &= -(int8_t)v; + if(v & 0x0F) unused -= 4; + if(v & 0x33) unused -= 2; + if(v & 0x55) unused -= 1; + tmp->size = b-st->buf + 1; + tmp->bits_unused = unused; + } else { + tmp->size = b-st->buf; + tmp->bits_unused = 0; + } + + assert(b >= st->buf); + } + + unconst.c_buf = st->buf; + tmp->buf = unconst.nc_buf; + return tmp; +} + +/* + * Lexicographically compare the common prefix of both strings, + * and if it is the same return -1 for the smallest string. + */ +int +BIT_STRING_compare(const asn_TYPE_descriptor_t *td, const void *aptr, + const void *bptr) { + /* + * Remove information about trailing bits, since + * X.680 (08/2015) #22.7 "ensure that different semantics are not" + * "associated with [values that differ only in] the trailing 0 bits." + */ + BIT_STRING_t compact_a, compact_b; + const BIT_STRING_t *a = BIT_STRING__compactify(aptr, &compact_a); + const BIT_STRING_t *b = BIT_STRING__compactify(bptr, &compact_b); + const asn_OCTET_STRING_specifics_t *specs = td->specifics; + + assert(specs && specs->subvariant == ASN_OSUBV_BIT); + + if(a && b) { + size_t common_prefix_size = a->size <= b->size ? a->size : b->size; + int ret = memcmp(a->buf, b->buf, common_prefix_size); + if(ret == 0) { + /* Figure out which string with equal prefixes is longer. */ + if(a->size < b->size) { + return -1; + } else if(a->size > b->size) { + return 1; + } else { + /* Figure out how many unused bits */ + if(a->bits_unused > b->bits_unused) { + return -1; + } else if(a->bits_unused < b->bits_unused) { + return 1; + } else { + return 0; + } + } + } else { + return ret; + } + } else if(!a && !b) { + return 0; + } else if(!a) { + return -1; + } else { + return 1; + } +} + +#ifndef ASN_DISABLE_PER_SUPPORT + +#undef RETURN +#define RETURN(_code) \ + do { \ + asn_dec_rval_t tmprval; \ + tmprval.code = _code; \ + tmprval.consumed = consumed_myself; \ + return tmprval; \ + } while(0) + +static asn_per_constraint_t asn_DEF_BIT_STRING_constraint_size = { + APC_SEMI_CONSTRAINED, -1, -1, 0, 0}; + +asn_dec_rval_t +BIT_STRING_decode_uper(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, + const asn_per_constraints_t *constraints, void **sptr, + asn_per_data_t *pd) { + const asn_OCTET_STRING_specifics_t *specs = td->specifics + ? (const asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_SPC_BIT_STRING_specs; + const asn_per_constraints_t *pc = + constraints ? constraints : td->encoding_constraints.per_constraints; + const asn_per_constraint_t *csiz; + asn_dec_rval_t rval = { RC_OK, 0 }; + BIT_STRING_t *st = (BIT_STRING_t *)*sptr; + ssize_t consumed_myself = 0; + int repeat; + + (void)opt_codec_ctx; + + if(pc) { + csiz = &pc->size; + } else { + csiz = &asn_DEF_BIT_STRING_constraint_size; + } + + if(specs->subvariant != ASN_OSUBV_BIT) { + ASN_DEBUG("Subvariant %d is not BIT OSUBV_BIT", specs->subvariant); + RETURN(RC_FAIL); + } + + /* + * Allocate the string. + */ + if(!st) { + st = (BIT_STRING_t *)(*sptr = CALLOC(1, specs->struct_size)); + if(!st) RETURN(RC_FAIL); + } + + ASN_DEBUG("PER Decoding %s size %ld .. %ld bits %d", + csiz->flags & APC_EXTENSIBLE ? "extensible" : "non-extensible", + csiz->lower_bound, csiz->upper_bound, csiz->effective_bits); + + if(csiz->flags & APC_EXTENSIBLE) { + int inext = per_get_few_bits(pd, 1); + if(inext < 0) RETURN(RC_WMORE); + if(inext) { + csiz = &asn_DEF_BIT_STRING_constraint_size; + } + } + + if(csiz->effective_bits >= 0) { + FREEMEM(st->buf); + st->size = (csiz->upper_bound + 7) >> 3; + st->buf = (uint8_t *)MALLOC(st->size + 1); + if(!st->buf) { st->size = 0; RETURN(RC_FAIL); } + } + + /* X.691, #16.5: zero-length encoding */ + /* X.691, #16.6: short fixed length encoding (up to 2 octets) */ + /* X.691, #16.7: long fixed length encoding (up to 64K octets) */ + if(csiz->effective_bits == 0) { + int ret; + ASN_DEBUG("Encoding BIT STRING size %ld", csiz->upper_bound); + ret = per_get_many_bits(pd, st->buf, 0, csiz->upper_bound); + if(ret < 0) RETURN(RC_WMORE); + consumed_myself += csiz->upper_bound; + st->buf[st->size] = 0; + st->bits_unused = (8 - (csiz->upper_bound & 0x7)) & 0x7; + RETURN(RC_OK); + } + + st->size = 0; + do { + ssize_t raw_len; + ssize_t len_bytes; + ssize_t len_bits; + void *p; + int ret; + + /* Get the PER length */ + raw_len = uper_get_length(pd, csiz->effective_bits, csiz->lower_bound, + &repeat); + if(raw_len < 0) RETURN(RC_WMORE); + if(raw_len == 0 && st->buf) break; + + ASN_DEBUG("Got PER length eb %ld, len %ld, %s (%s)", + (long)csiz->effective_bits, (long)raw_len, + repeat ? "repeat" : "once", td->name); + len_bits = raw_len; + len_bytes = (len_bits + 7) >> 3; + if(len_bits & 0x7) st->bits_unused = 8 - (len_bits & 0x7); + /* len_bits be multiple of 16K if repeat is set */ + p = REALLOC(st->buf, st->size + len_bytes + 1); + if(!p) RETURN(RC_FAIL); + st->buf = (uint8_t *)p; + + ret = per_get_many_bits(pd, &st->buf[st->size], 0, len_bits); + if(ret < 0) RETURN(RC_WMORE); + st->size += len_bytes; + } while(repeat); + st->buf[st->size] = 0; /* nul-terminate */ + + return rval; +} + +asn_enc_rval_t +BIT_STRING_encode_uper(const asn_TYPE_descriptor_t *td, + const asn_per_constraints_t *constraints, + const void *sptr, asn_per_outp_t *po) { + const asn_OCTET_STRING_specifics_t *specs = + td->specifics ? (const asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_SPC_BIT_STRING_specs; + const asn_per_constraints_t *pc = + constraints ? constraints : td->encoding_constraints.per_constraints; + const asn_per_constraint_t *csiz; + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + BIT_STRING_t compact_bstr; /* Do not modify this directly! */ + asn_enc_rval_t er = { 0, 0, 0 }; + int inext = 0; /* Lies not within extension root */ + size_t size_in_bits; + const uint8_t *buf; + int ret; + int ct_extensible; + + if(!st || (!st->buf && st->size)) + ASN__ENCODE_FAILED; + + if(specs->subvariant == ASN_OSUBV_BIT) { + if((st->size == 0 && st->bits_unused) || (st->bits_unused & ~7)) + ASN__ENCODE_FAILED; + } else { + ASN__ENCODE_FAILED; + } + + if(pc) { + csiz = &pc->size; + } else { + csiz = &asn_DEF_BIT_STRING_constraint_size; + } + ct_extensible = csiz->flags & APC_EXTENSIBLE; + + /* Figure out the size without the trailing bits */ + st = BIT_STRING__compactify(st, &compact_bstr); + size_in_bits = 8 * st->size - st->bits_unused; + + ASN_DEBUG( + "Encoding %s into %" ASN_PRI_SIZE " bits" + " (%ld..%ld, effective %d)%s", + td->name, size_in_bits, csiz->lower_bound, csiz->upper_bound, + csiz->effective_bits, ct_extensible ? " EXT" : ""); + + /* Figure out whether size lies within PER visible constraint */ + + if(csiz->effective_bits >= 0) { + if((ssize_t)size_in_bits > csiz->upper_bound) { + if(ct_extensible) { + csiz = &asn_DEF_BIT_STRING_constraint_size; + inext = 1; + } else { + ASN__ENCODE_FAILED; + } + } + } else { + inext = 0; + } + + if(ct_extensible) { + /* Declare whether length is [not] within extension root */ + if(per_put_few_bits(po, inext, 1)) + ASN__ENCODE_FAILED; + } + + if(csiz->effective_bits >= 0 && !inext) { + int add_trailer = (ssize_t)size_in_bits < csiz->lower_bound; + ASN_DEBUG( + "Encoding %" ASN_PRI_SIZE " bytes (%ld), length (in %d bits) trailer %d; actual " + "value %" ASN_PRI_SSIZE "", + st->size, size_in_bits - csiz->lower_bound, csiz->effective_bits, + add_trailer, + add_trailer ? 0 : (ssize_t)size_in_bits - csiz->lower_bound); + ret = per_put_few_bits( + po, add_trailer ? 0 : (ssize_t)size_in_bits - csiz->lower_bound, + csiz->effective_bits); + if(ret) ASN__ENCODE_FAILED; + ret = per_put_many_bits(po, st->buf, size_in_bits); + if(ret) ASN__ENCODE_FAILED; + if(add_trailer) { + static const uint8_t zeros[16]; + size_t trailing_zero_bits = csiz->lower_bound - size_in_bits; + while(trailing_zero_bits > 0) { + if(trailing_zero_bits > 8 * sizeof(zeros)) { + ret = per_put_many_bits(po, zeros, 8 * sizeof(zeros)); + trailing_zero_bits -= 8 * sizeof(zeros); + } else { + ret = per_put_many_bits(po, zeros, trailing_zero_bits); + trailing_zero_bits = 0; + } + if(ret) ASN__ENCODE_FAILED; + } + } + ASN__ENCODED_OK(er); + } + + ASN_DEBUG("Encoding %" ASN_PRI_SIZE " bytes", st->size); + + buf = st->buf; + do { + int need_eom = 0; + ssize_t maySave = uper_put_length(po, size_in_bits, &need_eom); + if(maySave < 0) ASN__ENCODE_FAILED; + + ASN_DEBUG("Encoding %" ASN_PRI_SSIZE " of %" ASN_PRI_SIZE "", maySave, size_in_bits); + + ret = per_put_many_bits(po, buf, maySave); + if(ret) ASN__ENCODE_FAILED; + + buf += maySave >> 3; + size_in_bits -= maySave; + assert(!(maySave & 0x07) || !size_in_bits); + if(need_eom && uper_put_length(po, 0, 0)) + ASN__ENCODE_FAILED; /* End of Message length */ + } while(size_in_bits); + + ASN__ENCODED_OK(er); +} + +#endif /* ASN_DISABLE_PER_SUPPORT */ + +asn_random_fill_result_t +BIT_STRING_random_fill(const asn_TYPE_descriptor_t *td, void **sptr, + const asn_encoding_constraints_t *constraints, + size_t max_length) { + const asn_OCTET_STRING_specifics_t *specs = + td->specifics ? (const asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_SPC_BIT_STRING_specs; + asn_random_fill_result_t result_ok = {ARFILL_OK, 1}; + asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0}; + asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0}; + static unsigned lengths[] = {0, 1, 2, 3, 4, 8, + 126, 127, 128, 16383, 16384, 16385, + 65534, 65535, 65536, 65537}; + uint8_t *buf; + uint8_t *bend; + uint8_t *b; + size_t rnd_bits, rnd_len; + BIT_STRING_t *st; + + if(max_length == 0) return result_skipped; + + switch(specs->subvariant) { + case ASN_OSUBV_ANY: + return result_failed; + case ASN_OSUBV_BIT: + break; + default: + break; + } + + /* Figure out how far we should go */ + rnd_bits = lengths[asn_random_between( + 0, sizeof(lengths) / sizeof(lengths[0]) - 1)]; + if(!constraints || !constraints->per_constraints) + constraints = &td->encoding_constraints; + if(constraints->per_constraints) { + const asn_per_constraint_t *pc = &constraints->per_constraints->size; + if(pc->flags & APC_CONSTRAINED) { + long suggested_upper_bound = pc->upper_bound < (ssize_t)max_length + ? pc->upper_bound + : (ssize_t)max_length; + if(max_length < (size_t)pc->lower_bound) { + return result_skipped; + } + if(pc->flags & APC_EXTENSIBLE) { + switch(asn_random_between(0, 5)) { + case 0: + if(pc->lower_bound > 0) { + rnd_bits = pc->lower_bound - 1; + break; + } + /* Fall through */ + case 1: + rnd_bits = pc->upper_bound + 1; + break; + case 2: + /* Keep rnd_bits from the table */ + if(rnd_bits < max_length) { + break; + } + /* Fall through */ + default: + rnd_bits = asn_random_between(pc->lower_bound, + suggested_upper_bound); + } + } else { + rnd_bits = + asn_random_between(pc->lower_bound, suggested_upper_bound); + } + } else { + rnd_bits = asn_random_between(0, max_length - 1); + } + } else if(rnd_bits >= max_length) { + rnd_bits = asn_random_between(0, max_length - 1); + } + + rnd_len = (rnd_bits + 7) / 8; + buf = CALLOC(1, rnd_len + 1); + if(!buf) return result_failed; + + bend = &buf[rnd_len]; + + for(b = buf; b < bend; b++) { + *(uint8_t *)b = asn_random_between(0, 255); + } + *b = 0; /* Zero-terminate just in case. */ + + if(*sptr) { + st = *sptr; + FREEMEM(st->buf); + } else { + st = (BIT_STRING_t *)(*sptr = CALLOC(1, specs->struct_size)); + if(!st) { + FREEMEM(buf); + return result_failed; + } + } + + st->buf = buf; + st->size = rnd_len; + st->bits_unused = (8 - (rnd_bits & 0x7)) & 0x7; + if(st->bits_unused) { + assert(st->size > 0); + st->buf[st->size-1] &= 0xff << st->bits_unused; + } + + result_ok.length = st->size; + return result_ok; +} diff --git a/Vendor/asn1/include/BIT_STRING.h b/Vendor/asn1/include/BIT_STRING.h new file mode 100644 index 0000000..bd2d23d --- /dev/null +++ b/Vendor/asn1/include/BIT_STRING.h @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 2003-2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _BIT_STRING_H_ +#define _BIT_STRING_H_ + +#include /* Some help from OCTET STRING */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct BIT_STRING_s { + uint8_t *buf; /* BIT STRING body */ + size_t size; /* Size of the above buffer */ + + int bits_unused;/* Unused trailing bits in the last octet (0..7) */ + + asn_struct_ctx_t _asn_ctx; /* Parsing across buffer boundaries */ +} BIT_STRING_t; + +extern asn_TYPE_descriptor_t asn_DEF_BIT_STRING; +extern asn_TYPE_operation_t asn_OP_BIT_STRING; +extern asn_OCTET_STRING_specifics_t asn_SPC_BIT_STRING_specs; + +asn_struct_print_f BIT_STRING_print; /* Human-readable output */ +asn_struct_compare_f BIT_STRING_compare; +asn_constr_check_f BIT_STRING_constraint; +xer_type_encoder_f BIT_STRING_encode_xer; +oer_type_decoder_f BIT_STRING_decode_oer; +oer_type_encoder_f BIT_STRING_encode_oer; +per_type_decoder_f BIT_STRING_decode_uper; +per_type_encoder_f BIT_STRING_encode_uper; +asn_random_fill_f BIT_STRING_random_fill; + +#define BIT_STRING_free OCTET_STRING_free +#define BIT_STRING_decode_ber OCTET_STRING_decode_ber +#define BIT_STRING_encode_der OCTET_STRING_encode_der +#define BIT_STRING_decode_xer OCTET_STRING_decode_xer_binary + +#ifdef __cplusplus +} +#endif + +#endif /* _BIT_STRING_H_ */ diff --git a/Vendor/asn1/include/INTEGER.c b/Vendor/asn1/include/INTEGER.c new file mode 100644 index 0000000..73da665 --- /dev/null +++ b/Vendor/asn1/include/INTEGER.c @@ -0,0 +1,1339 @@ +/*- + * Copyright (c) 2003-2014 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include /* Encoder and decoder of a primitive type */ +#include + +/* + * INTEGER basic type description. + */ +static const ber_tlv_tag_t asn_DEF_INTEGER_tags[] = { + (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)) +}; +asn_TYPE_operation_t asn_OP_INTEGER = { + INTEGER_free, + INTEGER_print, + INTEGER_compare, + ber_decode_primitive, + INTEGER_encode_der, + INTEGER_decode_xer, + INTEGER_encode_xer, +#ifdef ASN_DISABLE_OER_SUPPORT + 0, + 0, +#else + INTEGER_decode_oer, /* OER decoder */ + INTEGER_encode_oer, /* Canonical OER encoder */ +#endif /* ASN_DISABLE_OER_SUPPORT */ +#ifdef ASN_DISABLE_PER_SUPPORT + 0, + 0, +#else + INTEGER_decode_uper, /* Unaligned PER decoder */ + INTEGER_encode_uper, /* Unaligned PER encoder */ +#endif /* ASN_DISABLE_PER_SUPPORT */ + INTEGER_random_fill, + 0 /* Use generic outmost tag fetcher */ +}; +asn_TYPE_descriptor_t asn_DEF_INTEGER = { + "INTEGER", + "INTEGER", + &asn_OP_INTEGER, + asn_DEF_INTEGER_tags, + sizeof(asn_DEF_INTEGER_tags) / sizeof(asn_DEF_INTEGER_tags[0]), + asn_DEF_INTEGER_tags, /* Same as above */ + sizeof(asn_DEF_INTEGER_tags) / sizeof(asn_DEF_INTEGER_tags[0]), + { 0, 0, asn_generic_no_constraint }, + 0, 0, /* No members */ + 0 /* No specifics */ +}; + +/* + * Encode INTEGER type using DER. + */ +asn_enc_rval_t +INTEGER_encode_der(const asn_TYPE_descriptor_t *td, const void *sptr, + int tag_mode, ber_tlv_tag_t tag, asn_app_consume_bytes_f *cb, + void *app_key) { + const INTEGER_t *st = (const INTEGER_t *)sptr; + asn_enc_rval_t rval; + INTEGER_t effective_integer; + + ASN_DEBUG("%s %s as INTEGER (tm=%d)", + cb?"Encoding":"Estimating", td->name, tag_mode); + + /* + * Canonicalize integer in the buffer. + * (Remove too long sign extension, remove some first 0x00 bytes) + */ + if(st->buf) { + uint8_t *buf = st->buf; + uint8_t *end1 = buf + st->size - 1; + int shift; + + /* Compute the number of superfluous leading bytes */ + for(; buf < end1; buf++) { + /* + * If the contents octets of an integer value encoding + * consist of more than one octet, then the bits of the + * first octet and bit 8 of the second octet: + * a) shall not all be ones; and + * b) shall not all be zero. + */ + switch(*buf) { + case 0x00: if((buf[1] & 0x80) == 0) + continue; + break; + case 0xff: if((buf[1] & 0x80)) + continue; + break; + } + break; + } + + /* Remove leading superfluous bytes from the integer */ + shift = buf - st->buf; + if(shift) { + union { + const uint8_t *c_buf; + uint8_t *nc_buf; + } unconst; + unconst.c_buf = st->buf; + effective_integer.buf = unconst.nc_buf + shift; + effective_integer.size = st->size - shift; + + st = &effective_integer; + } + } + + rval = der_encode_primitive(td, st, tag_mode, tag, cb, app_key); + if(rval.structure_ptr == &effective_integer) { + rval.structure_ptr = sptr; + } + return rval; +} + +static const asn_INTEGER_enum_map_t *INTEGER_map_enum2value( + const asn_INTEGER_specifics_t *specs, const char *lstart, + const char *lstop); + +/* + * INTEGER specific human-readable output. + */ +static ssize_t +INTEGER__dump(const asn_TYPE_descriptor_t *td, const INTEGER_t *st, asn_app_consume_bytes_f *cb, void *app_key, int plainOrXER) { + const asn_INTEGER_specifics_t *specs = + (const asn_INTEGER_specifics_t *)td->specifics; + char scratch[32]; + uint8_t *buf = st->buf; + uint8_t *buf_end = st->buf + st->size; + intmax_t value; + ssize_t wrote = 0; + char *p; + int ret; + + if(specs && specs->field_unsigned) + ret = asn_INTEGER2umax(st, (uintmax_t *)&value); + else + ret = asn_INTEGER2imax(st, &value); + + /* Simple case: the integer size is small */ + if(ret == 0) { + const asn_INTEGER_enum_map_t *el; + el = (value >= 0 || !specs || !specs->field_unsigned) + ? INTEGER_map_value2enum(specs, value) : 0; + if(el) { + if(plainOrXER == 0) + return asn__format_to_callback(cb, app_key, + "%" ASN_PRIdMAX " (%s)", value, el->enum_name); + else + return asn__format_to_callback(cb, app_key, + "<%s/>", el->enum_name); + } else if(plainOrXER && specs && specs->strict_enumeration) { + ASN_DEBUG("ASN.1 forbids dealing with " + "unknown value of ENUMERATED type"); + errno = EPERM; + return -1; + } else { + return asn__format_to_callback(cb, app_key, + (specs && specs->field_unsigned) + ? "%" ASN_PRIuMAX + : "%" ASN_PRIdMAX, + value); + } + } else if(plainOrXER && specs && specs->strict_enumeration) { + /* + * Here and earlier, we cannot encode the ENUMERATED values + * if there is no corresponding identifier. + */ + ASN_DEBUG("ASN.1 forbids dealing with " + "unknown value of ENUMERATED type"); + errno = EPERM; + return -1; + } + + /* Output in the long xx:yy:zz... format */ + /* TODO: replace with generic algorithm (Knuth TAOCP Vol 2, 4.3.1) */ + for(p = scratch; buf < buf_end; buf++) { + const char * const h2c = "0123456789ABCDEF"; + if((p - scratch) >= (ssize_t)(sizeof(scratch) - 4)) { + /* Flush buffer */ + if(cb(scratch, p - scratch, app_key) < 0) + return -1; + wrote += p - scratch; + p = scratch; + } + *p++ = h2c[*buf >> 4]; + *p++ = h2c[*buf & 0x0F]; + *p++ = 0x3a; /* ":" */ + } + if(p != scratch) + p--; /* Remove the last ":" */ + + wrote += p - scratch; + return (cb(scratch, p - scratch, app_key) < 0) ? -1 : wrote; +} + +/* + * INTEGER specific human-readable output. + */ +int +INTEGER_print(const asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, + asn_app_consume_bytes_f *cb, void *app_key) { + const INTEGER_t *st = (const INTEGER_t *)sptr; + ssize_t ret; + + (void)ilevel; + + if(!st || !st->buf) + ret = cb("", 8, app_key); + else + ret = INTEGER__dump(td, st, cb, app_key, 0); + + return (ret < 0) ? -1 : 0; +} + +struct e2v_key { + const char *start; + const char *stop; + const asn_INTEGER_enum_map_t *vemap; + const unsigned int *evmap; +}; +static int +INTEGER__compar_enum2value(const void *kp, const void *am) { + const struct e2v_key *key = (const struct e2v_key *)kp; + const asn_INTEGER_enum_map_t *el = (const asn_INTEGER_enum_map_t *)am; + const char *ptr, *end, *name; + + /* Remap the element (sort by different criterion) */ + el = key->vemap + key->evmap[el - key->vemap]; + + /* Compare strings */ + for(ptr = key->start, end = key->stop, name = el->enum_name; + ptr < end; ptr++, name++) { + if(*ptr != *name || !*name) + return *(const unsigned char *)ptr + - *(const unsigned char *)name; + } + return name[0] ? -1 : 0; +} + +static const asn_INTEGER_enum_map_t * +INTEGER_map_enum2value(const asn_INTEGER_specifics_t *specs, const char *lstart, + const char *lstop) { + const asn_INTEGER_enum_map_t *el_found; + int count = specs ? specs->map_count : 0; + struct e2v_key key; + const char *lp; + + if(!count) return NULL; + + /* Guaranteed: assert(lstart < lstop); */ + /* Figure out the tag name */ + for(lstart++, lp = lstart; lp < lstop; lp++) { + switch(*lp) { + case 9: case 10: case 11: case 12: case 13: case 32: /* WSP */ + case 0x2f: /* '/' */ case 0x3e: /* '>' */ + break; + default: + continue; + } + break; + } + if(lp == lstop) return NULL; /* No tag found */ + lstop = lp; + + key.start = lstart; + key.stop = lstop; + key.vemap = specs->value2enum; + key.evmap = specs->enum2value; + el_found = (asn_INTEGER_enum_map_t *)bsearch(&key, + specs->value2enum, count, sizeof(specs->value2enum[0]), + INTEGER__compar_enum2value); + if(el_found) { + /* Remap enum2value into value2enum */ + el_found = key.vemap + key.evmap[el_found - key.vemap]; + } + return el_found; +} + +static int +INTEGER__compar_value2enum(const void *kp, const void *am) { + long a = *(const long *)kp; + const asn_INTEGER_enum_map_t *el = (const asn_INTEGER_enum_map_t *)am; + long b = el->nat_value; + if(a < b) return -1; + else if(a == b) return 0; + else return 1; +} + +const asn_INTEGER_enum_map_t * +INTEGER_map_value2enum(const asn_INTEGER_specifics_t *specs, long value) { + int count = specs ? specs->map_count : 0; + if(!count) return 0; + return (asn_INTEGER_enum_map_t *)bsearch(&value, specs->value2enum, + count, sizeof(specs->value2enum[0]), + INTEGER__compar_value2enum); +} + +static int +INTEGER_st_prealloc(INTEGER_t *st, int min_size) { + void *p = MALLOC(min_size + 1); + if(p) { + void *b = st->buf; + st->size = 0; + st->buf = p; + FREEMEM(b); + return 0; + } else { + return -1; + } +} + +/* + * Decode the chunk of XML text encoding INTEGER. + */ +static enum xer_pbd_rval +INTEGER__xer_body_decode(const asn_TYPE_descriptor_t *td, void *sptr, + const void *chunk_buf, size_t chunk_size) { + INTEGER_t *st = (INTEGER_t *)sptr; + intmax_t dec_value; + intmax_t hex_value = 0; + const char *lp; + const char *lstart = (const char *)chunk_buf; + const char *lstop = lstart + chunk_size; + enum { + ST_LEADSPACE, + ST_SKIPSPHEX, + ST_WAITDIGITS, + ST_DIGITS, + ST_DIGITS_TRAILSPACE, + ST_HEXDIGIT1, + ST_HEXDIGIT2, + ST_HEXDIGITS_TRAILSPACE, + ST_HEXCOLON, + ST_END_ENUM, + ST_UNEXPECTED + } state = ST_LEADSPACE; + const char *dec_value_start = 0; /* INVARIANT: always !0 in ST_DIGITS */ + const char *dec_value_end = 0; + + if(chunk_size) + ASN_DEBUG("INTEGER body %ld 0x%2x..0x%2x", + (long)chunk_size, *lstart, lstop[-1]); + + if(INTEGER_st_prealloc(st, (chunk_size/3) + 1)) + return XPBD_SYSTEM_FAILURE; + + /* + * We may have received a tag here. It will be processed inline. + * Use strtoul()-like code and serialize the result. + */ + for(lp = lstart; lp < lstop; lp++) { + int lv = *lp; + switch(lv) { + case 0x09: case 0x0a: case 0x0d: case 0x20: + switch(state) { + case ST_LEADSPACE: + case ST_DIGITS_TRAILSPACE: + case ST_HEXDIGITS_TRAILSPACE: + case ST_SKIPSPHEX: + continue; + case ST_DIGITS: + dec_value_end = lp; + state = ST_DIGITS_TRAILSPACE; + continue; + case ST_HEXCOLON: + state = ST_HEXDIGITS_TRAILSPACE; + continue; + default: + break; + } + break; + case 0x2d: /* '-' */ + if(state == ST_LEADSPACE) { + dec_value = 0; + dec_value_start = lp; + state = ST_WAITDIGITS; + continue; + } + break; + case 0x2b: /* '+' */ + if(state == ST_LEADSPACE) { + dec_value = 0; + dec_value_start = lp; + state = ST_WAITDIGITS; + continue; + } + break; + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: + case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: + switch(state) { + case ST_DIGITS: continue; + case ST_SKIPSPHEX: /* Fall through */ + case ST_HEXDIGIT1: + hex_value = (lv - 0x30) << 4; + state = ST_HEXDIGIT2; + continue; + case ST_HEXDIGIT2: + hex_value += (lv - 0x30); + state = ST_HEXCOLON; + st->buf[st->size++] = (uint8_t)hex_value; + continue; + case ST_HEXCOLON: + return XPBD_BROKEN_ENCODING; + case ST_LEADSPACE: + dec_value = 0; + dec_value_start = lp; + /* FALL THROUGH */ + case ST_WAITDIGITS: + state = ST_DIGITS; + continue; + default: + break; + } + break; + case 0x3c: /* '<', start of XML encoded enumeration */ + if(state == ST_LEADSPACE) { + const asn_INTEGER_enum_map_t *el; + el = INTEGER_map_enum2value( + (const asn_INTEGER_specifics_t *) + td->specifics, lstart, lstop); + if(el) { + ASN_DEBUG("Found \"%s\" => %ld", + el->enum_name, el->nat_value); + dec_value = el->nat_value; + state = ST_END_ENUM; + lp = lstop - 1; + continue; + } + ASN_DEBUG("Unknown identifier for INTEGER"); + } + return XPBD_BROKEN_ENCODING; + case 0x3a: /* ':' */ + if(state == ST_HEXCOLON) { + /* This colon is expected */ + state = ST_HEXDIGIT1; + continue; + } else if(state == ST_DIGITS) { + /* The colon here means that we have + * decoded the first two hexadecimal + * places as a decimal value. + * Switch decoding mode. */ + ASN_DEBUG("INTEGER re-evaluate as hex form"); + state = ST_SKIPSPHEX; + dec_value_start = 0; + lp = lstart - 1; + continue; + } else { + ASN_DEBUG("state %d at %ld", state, (long)(lp - lstart)); + break; + } + /* [A-Fa-f] */ + case 0x41:case 0x42:case 0x43:case 0x44:case 0x45:case 0x46: + case 0x61:case 0x62:case 0x63:case 0x64:case 0x65:case 0x66: + switch(state) { + case ST_SKIPSPHEX: + case ST_LEADSPACE: /* Fall through */ + case ST_HEXDIGIT1: + hex_value = lv - ((lv < 0x61) ? 0x41 : 0x61); + hex_value += 10; + hex_value <<= 4; + state = ST_HEXDIGIT2; + continue; + case ST_HEXDIGIT2: + hex_value += lv - ((lv < 0x61) ? 0x41 : 0x61); + hex_value += 10; + st->buf[st->size++] = (uint8_t)hex_value; + state = ST_HEXCOLON; + continue; + case ST_DIGITS: + ASN_DEBUG("INTEGER re-evaluate as hex form"); + state = ST_SKIPSPHEX; + dec_value_start = 0; + lp = lstart - 1; + continue; + default: + break; + } + break; + } + + /* Found extra non-numeric stuff */ + ASN_DEBUG("INTEGER :: Found non-numeric 0x%2x at %ld", + lv, (long)(lp - lstart)); + state = ST_UNEXPECTED; + break; + } + + switch(state) { + case ST_END_ENUM: + /* Got a complete and valid enumeration encoded as a tag. */ + break; + case ST_DIGITS: + dec_value_end = lstop; + /* FALL THROUGH */ + case ST_DIGITS_TRAILSPACE: + /* The last symbol encountered was a digit. */ + switch(asn_strtoimax_lim(dec_value_start, &dec_value_end, &dec_value)) { + case ASN_STRTOX_OK: + if(dec_value >= LONG_MIN && dec_value <= LONG_MAX) { + break; + } else { + /* + * We model INTEGER on long for XER, + * to avoid rewriting all the tests at once. + */ + ASN_DEBUG("INTEGER exceeds long range"); + } + /* Fall through */ + case ASN_STRTOX_ERROR_RANGE: + ASN_DEBUG("INTEGER decode %s hit range limit", td->name); + return XPBD_DECODER_LIMIT; + case ASN_STRTOX_ERROR_INVAL: + case ASN_STRTOX_EXPECT_MORE: + case ASN_STRTOX_EXTRA_DATA: + return XPBD_BROKEN_ENCODING; + } + break; + case ST_HEXCOLON: + case ST_HEXDIGITS_TRAILSPACE: + st->buf[st->size] = 0; /* Just in case termination */ + return XPBD_BODY_CONSUMED; + case ST_HEXDIGIT1: + case ST_HEXDIGIT2: + case ST_SKIPSPHEX: + return XPBD_BROKEN_ENCODING; + case ST_LEADSPACE: + /* Content not found */ + return XPBD_NOT_BODY_IGNORE; + case ST_WAITDIGITS: + case ST_UNEXPECTED: + ASN_DEBUG("INTEGER: No useful digits (state %d)", state); + return XPBD_BROKEN_ENCODING; /* No digits */ + } + + /* + * Convert the result of parsing of enumeration or a straight + * decimal value into a BER representation. + */ + if(asn_imax2INTEGER(st, dec_value)) { + ASN_DEBUG("INTEGER decode %s conversion failed", td->name); + return XPBD_SYSTEM_FAILURE; + } + + return XPBD_BODY_CONSUMED; +} + +asn_dec_rval_t +INTEGER_decode_xer(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, void **sptr, + const char *opt_mname, const void *buf_ptr, size_t size) { + return xer_decode_primitive(opt_codec_ctx, td, + sptr, sizeof(INTEGER_t), opt_mname, + buf_ptr, size, INTEGER__xer_body_decode); +} + +asn_enc_rval_t +INTEGER_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + const INTEGER_t *st = (const INTEGER_t *)sptr; + asn_enc_rval_t er; + + (void)ilevel; + (void)flags; + + if(!st || !st->buf) + ASN__ENCODE_FAILED; + + er.encoded = INTEGER__dump(td, st, cb, app_key, 1); + if(er.encoded < 0) ASN__ENCODE_FAILED; + + ASN__ENCODED_OK(er); +} + +#ifndef ASN_DISABLE_PER_SUPPORT + +asn_dec_rval_t +INTEGER_decode_uper(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, + const asn_per_constraints_t *constraints, void **sptr, + asn_per_data_t *pd) { + const asn_INTEGER_specifics_t *specs = + (const asn_INTEGER_specifics_t *)td->specifics; + asn_dec_rval_t rval = { RC_OK, 0 }; + INTEGER_t *st = (INTEGER_t *)*sptr; + const asn_per_constraint_t *ct; + int repeat; + + (void)opt_codec_ctx; + + if(!st) { + st = (INTEGER_t *)(*sptr = CALLOC(1, sizeof(*st))); + if(!st) ASN__DECODE_FAILED; + } + + if(!constraints) constraints = td->encoding_constraints.per_constraints; + ct = constraints ? &constraints->value : 0; + + if(ct && ct->flags & APC_EXTENSIBLE) { + int inext = per_get_few_bits(pd, 1); + if(inext < 0) ASN__DECODE_STARVED; + if(inext) ct = 0; + } + + FREEMEM(st->buf); + st->buf = 0; + st->size = 0; + if(ct) { + if(ct->flags & APC_SEMI_CONSTRAINED) { + st->buf = (uint8_t *)CALLOC(1, 2); + if(!st->buf) ASN__DECODE_FAILED; + st->size = 1; + } else if(ct->flags & APC_CONSTRAINED && ct->range_bits >= 0) { + size_t size = (ct->range_bits + 7) >> 3; + st->buf = (uint8_t *)MALLOC(1 + size + 1); + if(!st->buf) ASN__DECODE_FAILED; + st->size = size; + } + } + + /* X.691-2008/11, #13.2.2, constrained whole number */ + if(ct && ct->flags != APC_UNCONSTRAINED) { + /* #11.5.6 */ + ASN_DEBUG("Integer with range %d bits", ct->range_bits); + if(ct->range_bits >= 0) { + if((size_t)ct->range_bits > 8 * sizeof(unsigned long)) + ASN__DECODE_FAILED; + + if(specs && specs->field_unsigned) { + unsigned long uvalue = 0; + if(uper_get_constrained_whole_number(pd, + &uvalue, ct->range_bits)) + ASN__DECODE_STARVED; + ASN_DEBUG("Got value %lu + low %ld", + uvalue, ct->lower_bound); + uvalue += ct->lower_bound; + if(asn_ulong2INTEGER(st, uvalue)) + ASN__DECODE_FAILED; + } else { + unsigned long uvalue = 0; + long svalue; + if(uper_get_constrained_whole_number(pd, + &uvalue, ct->range_bits)) + ASN__DECODE_STARVED; + ASN_DEBUG("Got value %lu + low %ld", + uvalue, ct->lower_bound); + if(per_long_range_unrebase(uvalue, ct->lower_bound, + ct->upper_bound, &svalue) + || asn_long2INTEGER(st, svalue)) { + ASN__DECODE_FAILED; + } + } + return rval; + } + } else { + ASN_DEBUG("Decoding unconstrained integer %s", td->name); + } + + /* X.691, #12.2.3, #12.2.4 */ + do { + ssize_t len = 0; + void *p = NULL; + int ret = 0; + + /* Get the PER length */ + len = uper_get_length(pd, -1, 0, &repeat); + if(len < 0) ASN__DECODE_STARVED; + + p = REALLOC(st->buf, st->size + len + 1); + if(!p) ASN__DECODE_FAILED; + st->buf = (uint8_t *)p; + + ret = per_get_many_bits(pd, &st->buf[st->size], 0, 8 * len); + if(ret < 0) ASN__DECODE_STARVED; + st->size += len; + } while(repeat); + st->buf[st->size] = 0; /* JIC */ + + /* #12.2.3 */ + if(ct && ct->lower_bound) { + /* + * TODO: replace by in-place arithmetics. + */ + long value = 0; + if(asn_INTEGER2long(st, &value)) + ASN__DECODE_FAILED; + if(asn_imax2INTEGER(st, value + ct->lower_bound)) + ASN__DECODE_FAILED; + } + + return rval; +} + +asn_enc_rval_t +INTEGER_encode_uper(const asn_TYPE_descriptor_t *td, + const asn_per_constraints_t *constraints, const void *sptr, + asn_per_outp_t *po) { + const asn_INTEGER_specifics_t *specs = + (const asn_INTEGER_specifics_t *)td->specifics; + asn_enc_rval_t er; + const INTEGER_t *st = (const INTEGER_t *)sptr; + const uint8_t *buf; + const uint8_t *end; + const asn_per_constraint_t *ct; + long value = 0; + + if(!st || st->size == 0) ASN__ENCODE_FAILED; + + if(!constraints) constraints = td->encoding_constraints.per_constraints; + ct = constraints ? &constraints->value : 0; + + er.encoded = 0; + + if(ct) { + int inext = 0; + if(specs && specs->field_unsigned) { + unsigned long uval; + if(asn_INTEGER2ulong(st, &uval)) + ASN__ENCODE_FAILED; + /* Check proper range */ + if(ct->flags & APC_SEMI_CONSTRAINED) { + if(uval < (unsigned long)ct->lower_bound) + inext = 1; + } else if(ct->range_bits >= 0) { + if(uval < (unsigned long)ct->lower_bound + || uval > (unsigned long)ct->upper_bound) + inext = 1; + } + ASN_DEBUG("Value %lu (%02x/%" ASN_PRI_SIZE ") lb %lu ub %lu %s", + uval, st->buf[0], st->size, + ct->lower_bound, ct->upper_bound, + inext ? "ext" : "fix"); + value = uval; + } else { + if(asn_INTEGER2long(st, &value)) + ASN__ENCODE_FAILED; + /* Check proper range */ + if(ct->flags & APC_SEMI_CONSTRAINED) { + if(value < ct->lower_bound) + inext = 1; + } else if(ct->range_bits >= 0) { + if(value < ct->lower_bound + || value > ct->upper_bound) + inext = 1; + } + ASN_DEBUG("Value %ld (%02x/%" ASN_PRI_SIZE ") lb %ld ub %ld %s", + value, st->buf[0], st->size, + ct->lower_bound, ct->upper_bound, + inext ? "ext" : "fix"); + } + if(ct->flags & APC_EXTENSIBLE) { + if(per_put_few_bits(po, inext, 1)) + ASN__ENCODE_FAILED; + if(inext) ct = 0; + } else if(inext) { + ASN__ENCODE_FAILED; + } + } + + + /* X.691-11/2008, #13.2.2, test if constrained whole number */ + if(ct && ct->range_bits >= 0) { + unsigned long v; + /* #11.5.6 -> #11.3 */ + ASN_DEBUG("Encoding integer %ld (%lu) with range %d bits", + value, value - ct->lower_bound, ct->range_bits); + if(per_long_range_rebase(value, ct->lower_bound, ct->upper_bound, &v)) { + ASN__ENCODE_FAILED; + } + if(uper_put_constrained_whole_number_u(po, v, ct->range_bits)) + ASN__ENCODE_FAILED; + ASN__ENCODED_OK(er); + } + + if(ct && ct->lower_bound) { + ASN_DEBUG("Adjust lower bound to %ld", ct->lower_bound); + /* TODO: adjust lower bound */ + ASN__ENCODE_FAILED; + } + + for(buf = st->buf, end = st->buf + st->size; buf < end;) { + int need_eom = 0; + ssize_t mayEncode = uper_put_length(po, end - buf, &need_eom); + if(mayEncode < 0) + ASN__ENCODE_FAILED; + if(per_put_many_bits(po, buf, 8 * mayEncode)) + ASN__ENCODE_FAILED; + buf += mayEncode; + if(need_eom && uper_put_length(po, 0, 0)) ASN__ENCODE_FAILED; + } + + ASN__ENCODED_OK(er); +} + +#endif /* ASN_DISABLE_PER_SUPPORT */ + +static intmax_t +asn__integer_convert(const uint8_t *b, const uint8_t *end) { + uintmax_t value; + + /* Perform the sign initialization */ + /* Actually value = -(*b >> 7); gains nothing, yet unreadable! */ + if((*b >> 7)) { + value = (uintmax_t)(-1); + } else { + value = 0; + } + + /* Conversion engine */ + for(; b < end; b++) { + value = (value << 8) | *b; + } + + return value; +} + +int +asn_INTEGER2imax(const INTEGER_t *iptr, intmax_t *lptr) { + uint8_t *b, *end; + size_t size; + + /* Sanity checking */ + if(!iptr || !iptr->buf || !lptr) { + errno = EINVAL; + return -1; + } + + /* Cache the begin/end of the buffer */ + b = iptr->buf; /* Start of the INTEGER buffer */ + size = iptr->size; + end = b + size; /* Where to stop */ + + if(size > sizeof(intmax_t)) { + uint8_t *end1 = end - 1; + /* + * Slightly more advanced processing, + * able to process INTEGERs with >sizeof(intmax_t) bytes + * when the actual value is small, e.g. for intmax_t == int32_t + * (0x0000000000abcdef INTEGER would yield a fine 0x00abcdef int32_t) + */ + /* Skip out the insignificant leading bytes */ + for(; b < end1; b++) { + switch(*b) { + case 0x00: if((b[1] & 0x80) == 0) continue; break; + case 0xff: if((b[1] & 0x80) != 0) continue; break; + } + break; + } + + size = end - b; + if(size > sizeof(intmax_t)) { + /* Still cannot fit the sizeof(intmax_t) */ + errno = ERANGE; + return -1; + } + } + + /* Shortcut processing of a corner case */ + if(end == b) { + *lptr = 0; + return 0; + } + + *lptr = asn__integer_convert(b, end); + return 0; +} + +/* FIXME: negative INTEGER values are silently interpreted as large unsigned ones. */ +int +asn_INTEGER2umax(const INTEGER_t *iptr, uintmax_t *lptr) { + uint8_t *b, *end; + uintmax_t value; + size_t size; + + if(!iptr || !iptr->buf || !lptr) { + errno = EINVAL; + return -1; + } + + b = iptr->buf; + size = iptr->size; + end = b + size; + + /* If all extra leading bytes are zeroes, ignore them */ + for(; size > sizeof(value); b++, size--) { + if(*b) { + /* Value won't fit into uintmax_t */ + errno = ERANGE; + return -1; + } + } + + /* Conversion engine */ + for(value = 0; b < end; b++) + value = (value << 8) | *b; + + *lptr = value; + return 0; +} + +int +asn_umax2INTEGER(INTEGER_t *st, uintmax_t value) { + uint8_t *buf; + uint8_t *end; + uint8_t *b; + int shr; + + if(value <= ((~(uintmax_t)0) >> 1)) { + return asn_imax2INTEGER(st, value); + } + + buf = (uint8_t *)MALLOC(1 + sizeof(value)); + if(!buf) return -1; + + end = buf + (sizeof(value) + 1); + buf[0] = 0; /* INTEGERs are signed. 0-byte indicates positive. */ + for(b = buf + 1, shr = (sizeof(value) - 1) * 8; b < end; shr -= 8, b++) + *b = (uint8_t)(value >> shr); + + if(st->buf) FREEMEM(st->buf); + st->buf = buf; + st->size = 1 + sizeof(value); + + return 0; +} + +int +asn_imax2INTEGER(INTEGER_t *st, intmax_t value) { + uint8_t *buf, *bp; + uint8_t *p; + uint8_t *pstart; + uint8_t *pend1; + int littleEndian = 1; /* Run-time detection */ + int add; + + if(!st) { + errno = EINVAL; + return -1; + } + + buf = (uint8_t *)(long *)MALLOC(sizeof(value)); + if(!buf) return -1; + + if(*(char *)&littleEndian) { + pstart = (uint8_t *)&value + sizeof(value) - 1; + pend1 = (uint8_t *)&value; + add = -1; + } else { + pstart = (uint8_t *)&value; + pend1 = pstart + sizeof(value) - 1; + add = 1; + } + + /* + * If the contents octet consists of more than one octet, + * then bits of the first octet and bit 8 of the second octet: + * a) shall not all be ones; and + * b) shall not all be zero. + */ + for(p = pstart; p != pend1; p += add) { + switch(*p) { + case 0x00: if((*(p+add) & 0x80) == 0) + continue; + break; + case 0xff: if((*(p+add) & 0x80)) + continue; + break; + } + break; + } + /* Copy the integer body */ + for(bp = buf, pend1 += add; p != pend1; p += add) + *bp++ = *p; + + if(st->buf) FREEMEM(st->buf); + st->buf = buf; + st->size = bp - buf; + + return 0; +} + +int +asn_INTEGER2long(const INTEGER_t *iptr, long *l) { + intmax_t v; + if(asn_INTEGER2imax(iptr, &v) == 0) { + if(v < LONG_MIN || v > LONG_MAX) { + errno = ERANGE; + return -1; + } + *l = v; + return 0; + } else { + return -1; + } +} + +int +asn_INTEGER2ulong(const INTEGER_t *iptr, unsigned long *l) { + uintmax_t v; + if(asn_INTEGER2umax(iptr, &v) == 0) { + if(v > ULONG_MAX) { + errno = ERANGE; + return -1; + } + *l = v; + return 0; + } else { + return -1; + } +} + +int +asn_long2INTEGER(INTEGER_t *st, long value) { + return asn_imax2INTEGER(st, value); +} + +int +asn_ulong2INTEGER(INTEGER_t *st, unsigned long value) { + return asn_imax2INTEGER(st, value); +} + +/* + * Parse the number in the given string until the given *end position, + * returning the position after the last parsed character back using the + * same (*end) pointer. + * WARNING: This behavior is different from the standard strtol/strtoimax(3). + */ +enum asn_strtox_result_e +asn_strtoimax_lim(const char *str, const char **end, intmax_t *intp) { + int sign = 1; + intmax_t value; + +#define ASN1_INTMAX_MAX ((~(uintmax_t)0) >> 1) + const intmax_t upper_boundary = ASN1_INTMAX_MAX / 10; + intmax_t last_digit_max = ASN1_INTMAX_MAX % 10; +#undef ASN1_INTMAX_MAX + + if(str >= *end) return ASN_STRTOX_ERROR_INVAL; + + switch(*str) { + case '-': + last_digit_max++; + sign = -1; + /* FALL THROUGH */ + case '+': + str++; + if(str >= *end) { + *end = str; + return ASN_STRTOX_EXPECT_MORE; + } + } + + for(value = 0; str < (*end); str++) { + switch(*str) { + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: + case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: { + int d = *str - '0'; + if(value < upper_boundary) { + value = value * 10 + d; + } else if(value == upper_boundary) { + if(d <= last_digit_max) { + if(sign > 0) { + value = value * 10 + d; + } else { + sign = 1; + value = -value * 10 - d; + } + } else { + *end = str; + return ASN_STRTOX_ERROR_RANGE; + } + } else { + *end = str; + return ASN_STRTOX_ERROR_RANGE; + } + } + continue; + default: + *end = str; + *intp = sign * value; + return ASN_STRTOX_EXTRA_DATA; + } + } + + *end = str; + *intp = sign * value; + return ASN_STRTOX_OK; +} + +/* + * Parse the number in the given string until the given *end position, + * returning the position after the last parsed character back using the + * same (*end) pointer. + * WARNING: This behavior is different from the standard strtoul/strtoumax(3). + */ +enum asn_strtox_result_e +asn_strtoumax_lim(const char *str, const char **end, uintmax_t *uintp) { + uintmax_t value; + +#define ASN1_UINTMAX_MAX ((~(uintmax_t)0)) + const uintmax_t upper_boundary = ASN1_UINTMAX_MAX / 10; + uintmax_t last_digit_max = ASN1_UINTMAX_MAX % 10; +#undef ASN1_UINTMAX_MAX + + if(str >= *end) return ASN_STRTOX_ERROR_INVAL; + + switch(*str) { + case '-': + return ASN_STRTOX_ERROR_INVAL; + case '+': + str++; + if(str >= *end) { + *end = str; + return ASN_STRTOX_EXPECT_MORE; + } + } + + for(value = 0; str < (*end); str++) { + switch(*str) { + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: + case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: { + unsigned int d = *str - '0'; + if(value < upper_boundary) { + value = value * 10 + d; + } else if(value == upper_boundary) { + if(d <= last_digit_max) { + value = value * 10 + d; + } else { + *end = str; + return ASN_STRTOX_ERROR_RANGE; + } + } else { + *end = str; + return ASN_STRTOX_ERROR_RANGE; + } + } + continue; + default: + *end = str; + *uintp = value; + return ASN_STRTOX_EXTRA_DATA; + } + } + + *end = str; + *uintp = value; + return ASN_STRTOX_OK; +} + +enum asn_strtox_result_e +asn_strtol_lim(const char *str, const char **end, long *lp) { + intmax_t value; + switch(asn_strtoimax_lim(str, end, &value)) { + case ASN_STRTOX_ERROR_RANGE: + return ASN_STRTOX_ERROR_RANGE; + case ASN_STRTOX_ERROR_INVAL: + return ASN_STRTOX_ERROR_INVAL; + case ASN_STRTOX_EXPECT_MORE: + return ASN_STRTOX_EXPECT_MORE; + case ASN_STRTOX_OK: + if(value >= LONG_MIN && value <= LONG_MAX) { + *lp = value; + return ASN_STRTOX_OK; + } else { + return ASN_STRTOX_ERROR_RANGE; + } + case ASN_STRTOX_EXTRA_DATA: + if(value >= LONG_MIN && value <= LONG_MAX) { + *lp = value; + return ASN_STRTOX_EXTRA_DATA; + } else { + return ASN_STRTOX_ERROR_RANGE; + } + } + + assert(!"Unreachable"); + return ASN_STRTOX_ERROR_INVAL; +} + +enum asn_strtox_result_e +asn_strtoul_lim(const char *str, const char **end, unsigned long *ulp) { + uintmax_t value; + switch(asn_strtoumax_lim(str, end, &value)) { + case ASN_STRTOX_ERROR_RANGE: + return ASN_STRTOX_ERROR_RANGE; + case ASN_STRTOX_ERROR_INVAL: + return ASN_STRTOX_ERROR_INVAL; + case ASN_STRTOX_EXPECT_MORE: + return ASN_STRTOX_EXPECT_MORE; + case ASN_STRTOX_OK: + if(value <= ULONG_MAX) { + *ulp = value; + return ASN_STRTOX_OK; + } else { + return ASN_STRTOX_ERROR_RANGE; + } + case ASN_STRTOX_EXTRA_DATA: + if(value <= ULONG_MAX) { + *ulp = value; + return ASN_STRTOX_EXTRA_DATA; + } else { + return ASN_STRTOX_ERROR_RANGE; + } + } + + assert(!"Unreachable"); + return ASN_STRTOX_ERROR_INVAL; +} + +int +INTEGER_compare(const asn_TYPE_descriptor_t *td, const void *aptr, + const void *bptr) { + const INTEGER_t *a = aptr; + const INTEGER_t *b = bptr; + + (void)td; + + if(a && b) { + if(a->size && b->size) { + int sign_a = (a->buf[0] & 0x80) ? -1 : 1; + int sign_b = (b->buf[0] & 0x80) ? -1 : 1; + + if(sign_a < sign_b) return -1; + if(sign_a > sign_b) return 1; + + /* The shortest integer wins, unless comparing negatives */ + if(a->size < b->size) { + return -1 * sign_a; + } else if(a->size > b->size) { + return 1 * sign_b; + } + + return sign_a * memcmp(a->buf, b->buf, a->size); + } else if(a->size) { + int sign = (a->buf[0] & 0x80) ? -1 : 1; + return (1) * sign; + } else if(b->size) { + int sign = (a->buf[0] & 0x80) ? -1 : 1; + return (-1) * sign; + } else { + return 0; + } + } else if(!a && !b) { + return 0; + } else if(!a) { + return -1; + } else { + return 1; + } + +} + +asn_random_fill_result_t +INTEGER_random_fill(const asn_TYPE_descriptor_t *td, void **sptr, + const asn_encoding_constraints_t *constraints, + size_t max_length) { + const asn_INTEGER_specifics_t *specs = + (const asn_INTEGER_specifics_t *)td->specifics; + asn_random_fill_result_t result_ok = {ARFILL_OK, 1}; + asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0}; + asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0}; + INTEGER_t *st = *sptr; + const asn_INTEGER_enum_map_t *emap; + size_t emap_len; + intmax_t value; + int find_inside_map; + + if(max_length == 0) return result_skipped; + + if(st == NULL) { + st = (INTEGER_t *)CALLOC(1, sizeof(*st)); + if(st == NULL) { + return result_failed; + } + } + + if(specs) { + emap = specs->value2enum; + emap_len = specs->map_count; + if(specs->strict_enumeration) { + find_inside_map = emap_len > 0; + } else { + find_inside_map = emap_len ? asn_random_between(0, 1) : 0; + } + } else { + emap = 0; + emap_len = 0; + find_inside_map = 0; + } + + if(find_inside_map) { + assert(emap_len > 0); + value = emap[asn_random_between(0, emap_len - 1)].nat_value; + } else { + const asn_per_constraints_t *ct; + + static const long variants[] = { + -65536, -65535, -65534, -32769, -32768, -32767, -16385, -16384, + -16383, -257, -256, -255, -254, -129, -128, -127, + -126, -1, 0, 1, 126, 127, 128, 129, + 254, 255, 256, 257, 16383, 16384, 16385, 32767, + 32768, 32769, 65534, 65535, 65536, 65537}; + if(specs && specs->field_unsigned) { + assert(variants[18] == 0); + value = variants[asn_random_between( + 18, sizeof(variants) / sizeof(variants[0]) - 1)]; + } else { + value = variants[asn_random_between( + 0, sizeof(variants) / sizeof(variants[0]) - 1)]; + } + + if(!constraints) constraints = &td->encoding_constraints; + ct = constraints ? constraints->per_constraints : 0; + if(ct && (ct->value.flags & APC_CONSTRAINED)) { + if(value < ct->value.lower_bound || value > ct->value.upper_bound) { + value = asn_random_between(ct->value.lower_bound, + ct->value.upper_bound); + } + } + } + + if(asn_imax2INTEGER(st, value)) { + if(st == *sptr) { + ASN_STRUCT_RESET(*td, st); + } else { + ASN_STRUCT_FREE(*td, st); + } + return result_failed; + } else { + *sptr = st; + result_ok.length = st->size; + return result_ok; + } +} diff --git a/Vendor/asn1/include/INTEGER.h b/Vendor/asn1/include/INTEGER.h new file mode 100644 index 0000000..cc760ff --- /dev/null +++ b/Vendor/asn1/include/INTEGER.h @@ -0,0 +1,104 @@ +/*- + * Copyright (c) 2003-2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _INTEGER_H_ +#define _INTEGER_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef ASN__PRIMITIVE_TYPE_t INTEGER_t; + +extern asn_TYPE_descriptor_t asn_DEF_INTEGER; +extern asn_TYPE_operation_t asn_OP_INTEGER; + +/* Map with to integer value association */ +typedef struct asn_INTEGER_enum_map_s { + long nat_value; /* associated native integer value */ + size_t enum_len; /* strlen("tag") */ + const char *enum_name; /* "tag" */ +} asn_INTEGER_enum_map_t; + +/* This type describes an enumeration for INTEGER and ENUMERATED types */ +typedef struct asn_INTEGER_specifics_s { + const asn_INTEGER_enum_map_t *value2enum; /* N -> "tag"; sorted by N */ + const unsigned int *enum2value; /* "tag" => N; sorted by tag */ + int map_count; /* Elements in either map */ + int extension; /* This map is extensible */ + int strict_enumeration; /* Enumeration set is fixed */ + int field_width; /* Size of native integer */ + int field_unsigned; /* Signed=0, unsigned=1 */ +} asn_INTEGER_specifics_t; + +#define INTEGER_free ASN__PRIMITIVE_TYPE_free +#define INTEGER_decode_ber ber_decode_primitive +#define INTEGER_constraint asn_generic_no_constraint +asn_struct_print_f INTEGER_print; +asn_struct_compare_f INTEGER_compare; +der_type_encoder_f INTEGER_encode_der; +xer_type_decoder_f INTEGER_decode_xer; +xer_type_encoder_f INTEGER_encode_xer; +oer_type_decoder_f INTEGER_decode_oer; +oer_type_encoder_f INTEGER_encode_oer; +per_type_decoder_f INTEGER_decode_uper; +per_type_encoder_f INTEGER_encode_uper; +asn_random_fill_f INTEGER_random_fill; + +/*********************************** + * Some handy conversion routines. * + ***********************************/ + +/* + * Natiwe size-independent conversion of native integers to/from INTEGER. + * (l_size) is in bytes. + * Returns 0 if it was possible to convert, -1 otherwise. + * -1/EINVAL: Mandatory argument missing + * -1/ERANGE: Value encoded is out of range for long representation + * -1/ENOMEM: Memory allocation failed (in asn_*2INTEGER()). + */ +int asn_INTEGER2imax(const INTEGER_t *i, intmax_t *l); +int asn_INTEGER2umax(const INTEGER_t *i, uintmax_t *l); +int asn_imax2INTEGER(INTEGER_t *i, intmax_t l); +int asn_umax2INTEGER(INTEGER_t *i, uintmax_t l); + +/* + * Size-specific conversion helpers. + */ +int asn_INTEGER2long(const INTEGER_t *i, long *l); +int asn_INTEGER2ulong(const INTEGER_t *i, unsigned long *l); +int asn_long2INTEGER(INTEGER_t *i, long l); +int asn_ulong2INTEGER(INTEGER_t *i, unsigned long l); + +/* A version of strtol/strtoimax(3) with nicer error reporting. */ +enum asn_strtox_result_e { + ASN_STRTOX_ERROR_RANGE = -3, /* Input outside of supported numeric range */ + ASN_STRTOX_ERROR_INVAL = -2, /* Invalid data encountered (e.g., "+-") */ + ASN_STRTOX_EXPECT_MORE = -1, /* More data expected (e.g. "+") */ + ASN_STRTOX_OK = 0, /* Conversion succeded, number ends at (*end) */ + ASN_STRTOX_EXTRA_DATA = 1 /* Conversion succeded, but the string has extra stuff */ +}; +enum asn_strtox_result_e asn_strtol_lim(const char *str, const char **end, + long *l); +enum asn_strtox_result_e asn_strtoul_lim(const char *str, const char **end, + unsigned long *l); +enum asn_strtox_result_e asn_strtoimax_lim(const char *str, const char **end, + intmax_t *l); +enum asn_strtox_result_e asn_strtoumax_lim(const char *str, const char **end, + uintmax_t *l); + +/* + * Convert the integer value into the corresponding enumeration map entry. + */ +const asn_INTEGER_enum_map_t *INTEGER_map_value2enum( + const asn_INTEGER_specifics_t *specs, long value); + +#ifdef __cplusplus +} +#endif + +#endif /* _INTEGER_H_ */ diff --git a/Vendor/asn1/include/INTEGER_oer.c b/Vendor/asn1/include/INTEGER_oer.c new file mode 100644 index 0000000..5c98d3e --- /dev/null +++ b/Vendor/asn1/include/INTEGER_oer.c @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2017 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef ASN_DISABLE_OER_SUPPORT + +#include +#include +#include + +asn_dec_rval_t +INTEGER_decode_oer(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, + const asn_oer_constraints_t *constraints, void **sptr, + const void *ptr, size_t size) { + const asn_INTEGER_specifics_t *specs = + (const asn_INTEGER_specifics_t *)td->specifics; + asn_dec_rval_t rval = {RC_OK, 0}; + INTEGER_t *st = (INTEGER_t *)*sptr; + struct asn_oer_constraint_number_s ct = {0, 0}; + size_t req_bytes; + + (void)opt_codec_ctx; + (void)specs; + + if(!st) { + st = (INTEGER_t *)(*sptr = CALLOC(1, sizeof(*st))); + if(!st) ASN__DECODE_FAILED; + } + + FREEMEM(st->buf); + st->buf = 0; + st->size = 0; + + if(!constraints) constraints = td->encoding_constraints.oer_constraints; + if(constraints) ct = constraints->value; + + if(ct.width) { + req_bytes = ct.width; + } else { + /* No lower bound and no upper bound, effectively */ + + ssize_t consumed = oer_fetch_length(ptr, size, &req_bytes); + if(consumed == 0) { + ASN__DECODE_STARVED; + } else if(consumed == -1) { + ASN__DECODE_FAILED; + } + rval.consumed += consumed; + ptr = (const char *)ptr + consumed; + size -= consumed; + } + + if(req_bytes > size) { + ASN__DECODE_STARVED; + } + + if(ct.positive) { + /* X.969 08/2015 10.2(a) */ + unsigned msb; /* Most significant bit */ + size_t useful_size; + + /* Check most significant bit */ + msb = *(const uint8_t *)ptr >> 7; /* yields 0 or 1 */ + useful_size = msb + req_bytes; + st->buf = (uint8_t *)MALLOC(useful_size + 1); + if(!st->buf) { + ASN__DECODE_FAILED; + } + + /* + * Record a large unsigned in a way not to confuse it + * with signed value. + */ + st->buf[0] = '\0'; + memcpy(st->buf + msb, ptr, req_bytes); + st->buf[useful_size] = '\0'; /* Just in case, 0-terminate */ + st->size = useful_size; + + rval.consumed += req_bytes; + return rval; + } else { + /* X.969 08/2015 10.2(b) */ + st->buf = (uint8_t *)MALLOC(req_bytes + 1); + if(!st->buf) { + ASN__DECODE_FAILED; + } + + memcpy(st->buf, ptr, req_bytes); + st->buf[req_bytes] = '\0'; /* Just in case, 0-terminate */ + st->size = req_bytes; + + rval.consumed += req_bytes; + return rval; + } +} + +/* + * Encode as Canonical OER. + */ +asn_enc_rval_t +INTEGER_encode_oer(const asn_TYPE_descriptor_t *td, + const asn_oer_constraints_t *constraints, const void *sptr, + asn_app_consume_bytes_f *cb, void *app_key) { + const INTEGER_t *st = sptr; + asn_enc_rval_t er; + struct asn_oer_constraint_number_s ct = {0, 0}; + const uint8_t *buf; + const uint8_t *end; + size_t useful_bytes; + size_t req_bytes = 0; + int sign = 0; + + if(!st || st->size == 0) ASN__ENCODE_FAILED; + + if(!constraints) constraints = td->encoding_constraints.oer_constraints; + if(constraints) ct = constraints->value; + + er.encoded = 0; + + buf = st->buf; + end = buf + st->size; + + sign = (buf && buf < end) ? buf[0] & 0x80 : 0; + + /* Ignore 9 leading zeroes or ones */ + if(ct.positive) { + if(sign) { + /* The value given is a signed value. Can't proceed. */ + ASN__ENCODE_FAILED; + } + /* Remove leading zeros. */ + for(; buf + 1 < end; buf++) { + if(buf[0] != 0x0) break; + } + } else { + for(; buf + 1 < end; buf++) { + if(buf[0] == 0x0 && (buf[1] & 0x80) == 0) { + continue; + } else if(buf[0] == 0xff && (buf[1] & 0x80) != 0) { + continue; + } + break; + } + } + + useful_bytes = end - buf; + if(ct.width) { + req_bytes = ct.width; + } else { + ssize_t r = oer_serialize_length(useful_bytes, cb, app_key); + if(r < 0) { + ASN__ENCODE_FAILED; + } + er.encoded += r; + req_bytes = useful_bytes; + } + + if(req_bytes < useful_bytes) { + ASN__ENCODE_FAILED; + } + + er.encoded += req_bytes; + + for(; req_bytes > useful_bytes; req_bytes--) { + if(cb(sign?"\xff":"\0", 1, app_key) < 0) { + ASN__ENCODE_FAILED; + } + } + + if(cb(buf, useful_bytes, app_key) < 0) { + ASN__ENCODE_FAILED; + } + + ASN__ENCODED_OK(er); +} + +#endif /* ASN_DISABLE_OER_SUPPORT */ diff --git a/Vendor/asn1/include/Makefile.am.asn1convert b/Vendor/asn1/include/Makefile.am.asn1convert new file mode 100644 index 0000000..453f840 --- /dev/null +++ b/Vendor/asn1/include/Makefile.am.asn1convert @@ -0,0 +1,14 @@ +include Makefile.am.libasncodec + +bin_PROGRAMS += asn1convert +asn1convert_CFLAGS = $(ASN_MODULE_CFLAGS) -DASN_PDU_COLLECTION +asn1convert_CPPFLAGS = -I$(top_srcdir)/ +asn1convert_LDADD = libasncodec.la +asn1convert_SOURCES = \ + converter-example.c\ + pdu_collection.c +regen: regenerate-from-asn1-source + +regenerate-from-asn1-source: + asn1c -fnative-types ASN1PayloadStructure + diff --git a/Vendor/asn1/include/Makefile.am.libasncodec b/Vendor/asn1/include/Makefile.am.libasncodec new file mode 100644 index 0000000..7399541 --- /dev/null +++ b/Vendor/asn1/include/Makefile.am.libasncodec @@ -0,0 +1,86 @@ +ASN_MODULE_SRCS= \ + ReceiptAttribute.c \ + Payload.c + +ASN_MODULE_HDRS= \ + ReceiptAttribute.h \ + Payload.h + +ASN_MODULE_HDRS+=OPEN_TYPE.h +ASN_MODULE_SRCS+=OPEN_TYPE.c +ASN_MODULE_HDRS+=constr_CHOICE.h +ASN_MODULE_HDRS+=INTEGER.h +ASN_MODULE_SRCS+=INTEGER.c +ASN_MODULE_HDRS+=NativeInteger.h +ASN_MODULE_SRCS+=NativeInteger.c +ASN_MODULE_HDRS+=asn_SET_OF.h +ASN_MODULE_SRCS+=asn_SET_OF.c +ASN_MODULE_SRCS+=constr_CHOICE.c +ASN_MODULE_HDRS+=constr_SEQUENCE.h +ASN_MODULE_SRCS+=constr_SEQUENCE.c +ASN_MODULE_HDRS+=constr_SET_OF.h +ASN_MODULE_SRCS+=constr_SET_OF.c +ASN_MODULE_HDRS+=asn_application.h +ASN_MODULE_SRCS+=asn_application.c +ASN_MODULE_HDRS+=asn_ioc.h +ASN_MODULE_HDRS+=asn_system.h +ASN_MODULE_HDRS+=asn_codecs.h +ASN_MODULE_HDRS+=asn_internal.h +ASN_MODULE_SRCS+=asn_internal.c +ASN_MODULE_HDRS+=asn_random_fill.h +ASN_MODULE_SRCS+=asn_random_fill.c +ASN_MODULE_HDRS+=asn_bit_data.h +ASN_MODULE_SRCS+=asn_bit_data.c +ASN_MODULE_HDRS+=OCTET_STRING.h +ASN_MODULE_SRCS+=OCTET_STRING.c +ASN_MODULE_HDRS+=BIT_STRING.h +ASN_MODULE_SRCS+=BIT_STRING.c +ASN_MODULE_SRCS+=asn_codecs_prim.c +ASN_MODULE_HDRS+=asn_codecs_prim.h +ASN_MODULE_HDRS+=ber_tlv_length.h +ASN_MODULE_SRCS+=ber_tlv_length.c +ASN_MODULE_HDRS+=ber_tlv_tag.h +ASN_MODULE_SRCS+=ber_tlv_tag.c +ASN_MODULE_HDRS+=ber_decoder.h +ASN_MODULE_SRCS+=ber_decoder.c +ASN_MODULE_HDRS+=der_encoder.h +ASN_MODULE_SRCS+=der_encoder.c +ASN_MODULE_HDRS+=constr_TYPE.h +ASN_MODULE_SRCS+=constr_TYPE.c +ASN_MODULE_HDRS+=constraints.h +ASN_MODULE_SRCS+=constraints.c +ASN_MODULE_HDRS+=xer_support.h +ASN_MODULE_SRCS+=xer_support.c +ASN_MODULE_HDRS+=xer_decoder.h +ASN_MODULE_SRCS+=xer_decoder.c +ASN_MODULE_HDRS+=xer_encoder.h +ASN_MODULE_SRCS+=xer_encoder.c +ASN_MODULE_HDRS+=per_support.h +ASN_MODULE_SRCS+=per_support.c +ASN_MODULE_HDRS+=per_decoder.h +ASN_MODULE_SRCS+=per_decoder.c +ASN_MODULE_HDRS+=per_encoder.h +ASN_MODULE_SRCS+=per_encoder.c +ASN_MODULE_HDRS+=per_opentype.h +ASN_MODULE_SRCS+=per_opentype.c +ASN_MODULE_HDRS+=oer_decoder.h +ASN_MODULE_HDRS+=oer_encoder.h +ASN_MODULE_HDRS+=oer_support.h +ASN_MODULE_SRCS+=oer_decoder.c +ASN_MODULE_SRCS+=oer_encoder.c +ASN_MODULE_SRCS+=oer_support.c +ASN_MODULE_SRCS+=OPEN_TYPE_oer.c +ASN_MODULE_SRCS+=INTEGER_oer.c +ASN_MODULE_SRCS+=OCTET_STRING_oer.c +ASN_MODULE_SRCS+=NativeInteger_oer.c +ASN_MODULE_SRCS+=constr_CHOICE_oer.c +ASN_MODULE_SRCS+=constr_SEQUENCE_oer.c +ASN_MODULE_SRCS+=constr_SET_OF_oer.c + +ASN_MODULE_CFLAGS= + +lib_LTLIBRARIES+=libasncodec.la +libasncodec_la_SOURCES=$(ASN_MODULE_SRCS) $(ASN_MODULE_HDRS) +libasncodec_la_CPPFLAGS=-I$(top_srcdir)/ +libasncodec_la_CFLAGS=$(ASN_MODULE_CFLAGS) +libasncodec_la_LDFLAGS=-lm diff --git a/Vendor/asn1/include/NativeInteger.c b/Vendor/asn1/include/NativeInteger.c new file mode 100644 index 0000000..f172437 --- /dev/null +++ b/Vendor/asn1/include/NativeInteger.c @@ -0,0 +1,484 @@ +/*- + * Copyright (c) 2004, 2005, 2006 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +/* + * Read the NativeInteger.h for the explanation wrt. differences between + * INTEGER and NativeInteger. + * Basically, both are decoders and encoders of ASN.1 INTEGER type, but this + * implementation deals with the standard (machine-specific) representation + * of them instead of using the platform-independent buffer. + */ +#include +#include + +/* + * NativeInteger basic type description. + */ +static const ber_tlv_tag_t asn_DEF_NativeInteger_tags[] = { + (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)) +}; +asn_TYPE_operation_t asn_OP_NativeInteger = { + NativeInteger_free, + NativeInteger_print, + NativeInteger_compare, + NativeInteger_decode_ber, + NativeInteger_encode_der, + NativeInteger_decode_xer, + NativeInteger_encode_xer, +#ifdef ASN_DISABLE_OER_SUPPORT + 0, + 0, +#else + NativeInteger_decode_oer, /* OER decoder */ + NativeInteger_encode_oer, /* Canonical OER encoder */ +#endif /* ASN_DISABLE_OER_SUPPORT */ +#ifdef ASN_DISABLE_PER_SUPPORT + 0, + 0, +#else + NativeInteger_decode_uper, /* Unaligned PER decoder */ + NativeInteger_encode_uper, /* Unaligned PER encoder */ +#endif /* ASN_DISABLE_PER_SUPPORT */ + NativeInteger_random_fill, + 0 /* Use generic outmost tag fetcher */ +}; +asn_TYPE_descriptor_t asn_DEF_NativeInteger = { + "INTEGER", /* The ASN.1 type is still INTEGER */ + "INTEGER", + &asn_OP_NativeInteger, + asn_DEF_NativeInteger_tags, + sizeof(asn_DEF_NativeInteger_tags) / sizeof(asn_DEF_NativeInteger_tags[0]), + asn_DEF_NativeInteger_tags, /* Same as above */ + sizeof(asn_DEF_NativeInteger_tags) / sizeof(asn_DEF_NativeInteger_tags[0]), + { 0, 0, asn_generic_no_constraint }, + 0, 0, /* No members */ + 0 /* No specifics */ +}; + +/* + * Decode INTEGER type. + */ +asn_dec_rval_t +NativeInteger_decode_ber(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, void **nint_ptr, + const void *buf_ptr, size_t size, int tag_mode) { + const asn_INTEGER_specifics_t *specs = + (const asn_INTEGER_specifics_t *)td->specifics; + long *native = (long *)*nint_ptr; + asn_dec_rval_t rval; + ber_tlv_len_t length; + + /* + * If the structure is not there, allocate it. + */ + if(native == NULL) { + native = (long *)(*nint_ptr = CALLOC(1, sizeof(*native))); + if(native == NULL) { + rval.code = RC_FAIL; + rval.consumed = 0; + return rval; + } + } + + ASN_DEBUG("Decoding %s as INTEGER (tm=%d)", + td->name, tag_mode); + + /* + * Check tags. + */ + rval = ber_check_tags(opt_codec_ctx, td, 0, buf_ptr, size, + tag_mode, 0, &length, 0); + if(rval.code != RC_OK) + return rval; + + ASN_DEBUG("%s length is %d bytes", td->name, (int)length); + + /* + * Make sure we have this length. + */ + buf_ptr = ((const char *)buf_ptr) + rval.consumed; + size -= rval.consumed; + if(length > (ber_tlv_len_t)size) { + rval.code = RC_WMORE; + rval.consumed = 0; + return rval; + } + + /* + * ASN.1 encoded INTEGER: buf_ptr, length + * Fill the native, at the same time checking for overflow. + * If overflow occured, return with RC_FAIL. + */ + { + INTEGER_t tmp; + union { + const void *constbuf; + void *nonconstbuf; + } unconst_buf; + long l; + + unconst_buf.constbuf = buf_ptr; + tmp.buf = (uint8_t *)unconst_buf.nonconstbuf; + tmp.size = length; + + if((specs&&specs->field_unsigned) + ? asn_INTEGER2ulong(&tmp, (unsigned long *)&l) /* sic */ + : asn_INTEGER2long(&tmp, &l)) { + rval.code = RC_FAIL; + rval.consumed = 0; + return rval; + } + + *native = l; + } + + rval.code = RC_OK; + rval.consumed += length; + + ASN_DEBUG("Took %ld/%ld bytes to encode %s (%ld)", + (long)rval.consumed, (long)length, td->name, (long)*native); + + return rval; +} + +/* + * Encode the NativeInteger using the standard INTEGER type DER encoder. + */ +asn_enc_rval_t +NativeInteger_encode_der(const asn_TYPE_descriptor_t *sd, const void *ptr, + int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + unsigned long native = *(const unsigned long *)ptr; /* Disable sign ext. */ + asn_enc_rval_t erval; + INTEGER_t tmp; + +#ifdef WORDS_BIGENDIAN /* Opportunistic optimization */ + + tmp.buf = (uint8_t *)&native; + tmp.size = sizeof(native); + +#else /* Works even if WORDS_BIGENDIAN is not set where should've been */ + uint8_t buf[sizeof(native)]; + uint8_t *p; + + /* Prepare a fake INTEGER */ + for(p = buf + sizeof(buf) - 1; p >= buf; p--, native >>= 8) + *p = (uint8_t)native; + + tmp.buf = buf; + tmp.size = sizeof(buf); +#endif /* WORDS_BIGENDIAN */ + + /* Encode fake INTEGER */ + erval = INTEGER_encode_der(sd, &tmp, tag_mode, tag, cb, app_key); + if(erval.structure_ptr == &tmp) { + erval.structure_ptr = ptr; + } + return erval; +} + +/* + * Decode the chunk of XML text encoding INTEGER. + */ +asn_dec_rval_t +NativeInteger_decode_xer(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, void **sptr, + const char *opt_mname, const void *buf_ptr, + size_t size) { + const asn_INTEGER_specifics_t *specs = + (const asn_INTEGER_specifics_t *)td->specifics; + asn_dec_rval_t rval; + INTEGER_t st; + void *st_ptr = (void *)&st; + long *native = (long *)*sptr; + + if(!native) { + native = (long *)(*sptr = CALLOC(1, sizeof(*native))); + if(!native) ASN__DECODE_FAILED; + } + + memset(&st, 0, sizeof(st)); + rval = INTEGER_decode_xer(opt_codec_ctx, td, &st_ptr, + opt_mname, buf_ptr, size); + if(rval.code == RC_OK) { + long l; + if((specs&&specs->field_unsigned) + ? asn_INTEGER2ulong(&st, (unsigned long *)&l) /* sic */ + : asn_INTEGER2long(&st, &l)) { + rval.code = RC_FAIL; + rval.consumed = 0; + } else { + *native = l; + } + } else { + /* + * Cannot restart from the middle; + * there is no place to save state in the native type. + * Request a continuation from the very beginning. + */ + rval.consumed = 0; + } + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &st); + return rval; +} + + +asn_enc_rval_t +NativeInteger_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + const asn_INTEGER_specifics_t *specs = + (const asn_INTEGER_specifics_t *)td->specifics; + char scratch[32]; /* Enough for 64-bit int */ + asn_enc_rval_t er; + const long *native = (const long *)sptr; + + (void)ilevel; + (void)flags; + + if(!native) ASN__ENCODE_FAILED; + + er.encoded = snprintf(scratch, sizeof(scratch), + (specs && specs->field_unsigned) + ? "%lu" : "%ld", *native); + if(er.encoded <= 0 || (size_t)er.encoded >= sizeof(scratch) + || cb(scratch, er.encoded, app_key) < 0) + ASN__ENCODE_FAILED; + + ASN__ENCODED_OK(er); +} + +#ifndef ASN_DISABLE_PER_SUPPORT + +asn_dec_rval_t +NativeInteger_decode_uper(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, + const asn_per_constraints_t *constraints, void **sptr, + asn_per_data_t *pd) { + const asn_INTEGER_specifics_t *specs = + (const asn_INTEGER_specifics_t *)td->specifics; + asn_dec_rval_t rval; + long *native = (long *)*sptr; + INTEGER_t tmpint; + void *tmpintptr = &tmpint; + + (void)opt_codec_ctx; + ASN_DEBUG("Decoding NativeInteger %s (UPER)", td->name); + + if(!native) { + native = (long *)(*sptr = CALLOC(1, sizeof(*native))); + if(!native) ASN__DECODE_FAILED; + } + + memset(&tmpint, 0, sizeof tmpint); + rval = INTEGER_decode_uper(opt_codec_ctx, td, constraints, + &tmpintptr, pd); + if(rval.code == RC_OK) { + if((specs&&specs->field_unsigned) + ? asn_INTEGER2ulong(&tmpint, (unsigned long *)native) + : asn_INTEGER2long(&tmpint, native)) + rval.code = RC_FAIL; + else + ASN_DEBUG("NativeInteger %s got value %ld", + td->name, *native); + } + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &tmpint); + + return rval; +} + +asn_enc_rval_t +NativeInteger_encode_uper(const asn_TYPE_descriptor_t *td, + const asn_per_constraints_t *constraints, + const void *sptr, asn_per_outp_t *po) { + const asn_INTEGER_specifics_t *specs = + (const asn_INTEGER_specifics_t *)td->specifics; + asn_enc_rval_t er; + long native; + INTEGER_t tmpint; + + if(!sptr) ASN__ENCODE_FAILED; + + native = *(const long *)sptr; + + ASN_DEBUG("Encoding NativeInteger %s %ld (UPER)", td->name, native); + + memset(&tmpint, 0, sizeof(tmpint)); + if((specs&&specs->field_unsigned) + ? asn_ulong2INTEGER(&tmpint, native) + : asn_long2INTEGER(&tmpint, native)) + ASN__ENCODE_FAILED; + er = INTEGER_encode_uper(td, constraints, &tmpint, po); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &tmpint); + return er; +} + +#endif /* ASN_DISABLE_PER_SUPPORT */ + +/* + * INTEGER specific human-readable output. + */ +int +NativeInteger_print(const asn_TYPE_descriptor_t *td, const void *sptr, + int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { + const asn_INTEGER_specifics_t *specs = + (const asn_INTEGER_specifics_t *)td->specifics; + const long *native = (const long *)sptr; + char scratch[32]; /* Enough for 64-bit int */ + int ret; + + (void)td; /* Unused argument */ + (void)ilevel; /* Unused argument */ + + if(native) { + long value = *native; + ret = snprintf(scratch, sizeof(scratch), + (specs && specs->field_unsigned) ? "%lu" : "%ld", value); + assert(ret > 0 && (size_t)ret < sizeof(scratch)); + if(cb(scratch, ret, app_key) < 0) return -1; + if(specs && (value >= 0 || !specs->field_unsigned)) { + const asn_INTEGER_enum_map_t *el = + INTEGER_map_value2enum(specs, value); + if(el) { + if(cb(" (", 2, app_key) < 0) return -1; + if(cb(el->enum_name, el->enum_len, app_key) < 0) return -1; + if(cb(")", 1, app_key) < 0) return -1; + } + } + return 0; + } else { + return (cb("", 8, app_key) < 0) ? -1 : 0; + } +} + +void +NativeInteger_free(const asn_TYPE_descriptor_t *td, void *ptr, + enum asn_struct_free_method method) { + if(!td || !ptr) + return; + + ASN_DEBUG("Freeing %s as INTEGER (%d, %p, Native)", + td->name, method, ptr); + + switch(method) { + case ASFM_FREE_EVERYTHING: + FREEMEM(ptr); + break; + case ASFM_FREE_UNDERLYING: + break; + case ASFM_FREE_UNDERLYING_AND_RESET: + memset(ptr, 0, sizeof(long)); + break; + } +} + +int +NativeInteger_compare(const asn_TYPE_descriptor_t *td, const void *aptr, const void *bptr) { + (void)td; + + if(aptr && bptr) { + const asn_INTEGER_specifics_t *specs = + (const asn_INTEGER_specifics_t *)td->specifics; + if(specs && specs->field_unsigned) { + const unsigned long *a = aptr; + const unsigned long *b = bptr; + if(*a < *b) { + return -1; + } else if(*a > *b) { + return 1; + } else { + return 0; + } + } else { + const long *a = aptr; + const long *b = bptr; + if(*a < *b) { + return -1; + } else if(*a > *b) { + return 1; + } else { + return 0; + } + } + } else if(!aptr) { + return -1; + } else { + return 1; + } +} + +asn_random_fill_result_t +NativeInteger_random_fill(const asn_TYPE_descriptor_t *td, void **sptr, + const asn_encoding_constraints_t *constraints, + size_t max_length) { + const asn_INTEGER_specifics_t *specs = + (const asn_INTEGER_specifics_t *)td->specifics; + asn_random_fill_result_t result_ok = {ARFILL_OK, 1}; + asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0}; + asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0}; + long *st = *sptr; + const asn_INTEGER_enum_map_t *emap; + size_t emap_len; + intmax_t value; + int find_inside_map; + + if(max_length == 0) return result_skipped; + + if(st == NULL) { + st = (long *)CALLOC(1, sizeof(*st)); + if(st == NULL) { + return result_failed; + } + } + + if(specs) { + emap = specs->value2enum; + emap_len = specs->map_count; + if(specs->strict_enumeration) { + find_inside_map = emap_len > 0; + } else { + find_inside_map = emap_len ? asn_random_between(0, 1) : 0; + } + } else { + emap = 0; + emap_len = 0; + find_inside_map = 0; + } + + if(find_inside_map) { + assert(emap_len > 0); + value = emap[asn_random_between(0, emap_len - 1)].nat_value; + } else { + const asn_per_constraints_t *ct; + + static const long variants[] = { + -65536, -65535, -65534, -32769, -32768, -32767, -16385, -16384, + -16383, -257, -256, -255, -254, -129, -128, -127, + -126, -1, 0, 1, 126, 127, 128, 129, + 254, 255, 256, 257, 16383, 16384, 16385, 32767, + 32768, 32769, 65534, 65535, 65536, 65537}; + if(specs && specs->field_unsigned) { + assert(variants[18] == 0); + value = variants[asn_random_between( + 18, sizeof(variants) / sizeof(variants[0]) - 1)]; + } else { + value = variants[asn_random_between( + 0, sizeof(variants) / sizeof(variants[0]) - 1)]; + } + + if(!constraints) constraints = &td->encoding_constraints; + ct = constraints ? constraints->per_constraints : 0; + if(ct && (ct->value.flags & APC_CONSTRAINED)) { + if(value < ct->value.lower_bound || value > ct->value.upper_bound) { + value = asn_random_between(ct->value.lower_bound, + ct->value.upper_bound); + } + } + } + + *sptr = st; + *st = value; + return result_ok; +} diff --git a/Vendor/asn1/include/NativeInteger.h b/Vendor/asn1/include/NativeInteger.h new file mode 100644 index 0000000..e2741c2 --- /dev/null +++ b/Vendor/asn1/include/NativeInteger.h @@ -0,0 +1,44 @@ +/*- + * Copyright (c) 2004-2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +/* + * This type differs from the standard INTEGER in that it is modelled using + * the fixed machine type (long, int, short), so it can hold only values of + * limited length. There is no type (i.e., NativeInteger_t, any integer type + * will do). + * This type may be used when integer range is limited by subtype constraints. + */ +#ifndef _NativeInteger_H_ +#define _NativeInteger_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern asn_TYPE_descriptor_t asn_DEF_NativeInteger; +extern asn_TYPE_operation_t asn_OP_NativeInteger; + +asn_struct_free_f NativeInteger_free; +asn_struct_print_f NativeInteger_print; +asn_struct_compare_f NativeInteger_compare; +ber_type_decoder_f NativeInteger_decode_ber; +der_type_encoder_f NativeInteger_encode_der; +xer_type_decoder_f NativeInteger_decode_xer; +xer_type_encoder_f NativeInteger_encode_xer; +oer_type_decoder_f NativeInteger_decode_oer; +oer_type_encoder_f NativeInteger_encode_oer; +per_type_decoder_f NativeInteger_decode_uper; +per_type_encoder_f NativeInteger_encode_uper; +asn_random_fill_f NativeInteger_random_fill; + +#define NativeInteger_constraint asn_generic_no_constraint + +#ifdef __cplusplus +} +#endif + +#endif /* _NativeInteger_H_ */ diff --git a/Vendor/asn1/include/NativeInteger_oer.c b/Vendor/asn1/include/NativeInteger_oer.c new file mode 100644 index 0000000..411413a --- /dev/null +++ b/Vendor/asn1/include/NativeInteger_oer.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2017 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef ASN_DISABLE_OER_SUPPORT + +#include +#include +#include + +asn_dec_rval_t +NativeInteger_decode_oer(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, + const asn_oer_constraints_t *constraints, + void **nint_ptr, const void *ptr, size_t size) { + const asn_INTEGER_specifics_t *specs = + (const asn_INTEGER_specifics_t *)td->specifics; + asn_dec_rval_t rval = {RC_OK, 0}; + long *native = (long *)*nint_ptr; + INTEGER_t tmpint; + INTEGER_t *tmpintptr = &tmpint; + + memset(&tmpint, 0, sizeof(tmpint)); + + if(!native) { + native = (long *)(*nint_ptr = CALLOC(1, sizeof(*native))); + if(!native) ASN__DECODE_FAILED; + } + + /* + * OPTIMIZATION: Encode directly rather than passing through INTEGER. + * Saves a memory allocation. + */ + rval = INTEGER_decode_oer(opt_codec_ctx, td, constraints, + (void **)&tmpintptr, ptr, size); + if(rval.code != RC_OK) { + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &tmpint); + return rval; + } + + if(specs && specs->field_unsigned) { + unsigned long ul; + int ok = asn_INTEGER2ulong(&tmpint, &ul) == 0; + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &tmpint); + if(ok) { + *native = ul; + } else { + rval.code = RC_FAIL; + return rval; + } + } else { + long l; + int ok = asn_INTEGER2long(&tmpint, &l) == 0; + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &tmpint); + if(ok) { + *native = l; + } else { + rval.code = RC_FAIL; + return rval; + } + } + + return rval; +} + +/* + * Encode as Canonical OER. + */ +asn_enc_rval_t +NativeInteger_encode_oer(const asn_TYPE_descriptor_t *td, + const asn_oer_constraints_t *constraints, + const void *sptr, asn_app_consume_bytes_f *cb, + void *app_key) { + const asn_INTEGER_specifics_t *specs = + (const asn_INTEGER_specifics_t *)td->specifics; + INTEGER_t tmpint; + long native; + + if(!sptr) ASN__ENCODE_FAILED; + + native = *(const long *)sptr; + memset(&tmpint, 0, sizeof(tmpint)); + + ASN_DEBUG("Encoding %s %ld as NativeInteger", td ? td->name : "", native); + + if((specs && specs->field_unsigned) ? asn_ulong2INTEGER(&tmpint, native) + : asn_long2INTEGER(&tmpint, native)) { + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &tmpint); + ASN__ENCODE_FAILED; + } else { + asn_enc_rval_t er = + INTEGER_encode_oer(td, constraints, &tmpint, cb, app_key); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &tmpint); + return er; + } +} + +#endif /* ASN_DISABLE_OER_SUPPORT */ diff --git a/Vendor/asn1/include/OCTET_STRING.c b/Vendor/asn1/include/OCTET_STRING.c new file mode 100644 index 0000000..a692851 --- /dev/null +++ b/Vendor/asn1/include/OCTET_STRING.c @@ -0,0 +1,2043 @@ +/*- + * Copyright (c) 2003-2017 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include /* for .bits_unused member */ +#include + +/* + * OCTET STRING basic type description. + */ +static const ber_tlv_tag_t asn_DEF_OCTET_STRING_tags[] = { + (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)) +}; +asn_OCTET_STRING_specifics_t asn_SPC_OCTET_STRING_specs = { + sizeof(OCTET_STRING_t), + offsetof(OCTET_STRING_t, _asn_ctx), + ASN_OSUBV_STR +}; + +asn_TYPE_operation_t asn_OP_OCTET_STRING = { + OCTET_STRING_free, + OCTET_STRING_print, /* OCTET STRING generally means a non-ascii sequence */ + OCTET_STRING_compare, + OCTET_STRING_decode_ber, + OCTET_STRING_encode_der, + OCTET_STRING_decode_xer_hex, + OCTET_STRING_encode_xer, +#ifdef ASN_DISABLE_OER_SUPPORT + 0, + 0, +#else + OCTET_STRING_decode_oer, + OCTET_STRING_encode_oer, +#endif /* ASN_DISABLE_OER_SUPPORT */ +#ifdef ASN_DISABLE_PER_SUPPORT + 0, + 0, +#else + OCTET_STRING_decode_uper, /* Unaligned PER decoder */ + OCTET_STRING_encode_uper, /* Unaligned PER encoder */ +#endif /* ASN_DISABLE_PER_SUPPORT */ + OCTET_STRING_random_fill, + 0 /* Use generic outmost tag fetcher */ +}; +asn_TYPE_descriptor_t asn_DEF_OCTET_STRING = { + "OCTET STRING", /* Canonical name */ + "OCTET_STRING", /* XML tag name */ + &asn_OP_OCTET_STRING, + asn_DEF_OCTET_STRING_tags, + sizeof(asn_DEF_OCTET_STRING_tags) + / sizeof(asn_DEF_OCTET_STRING_tags[0]), + asn_DEF_OCTET_STRING_tags, /* Same as above */ + sizeof(asn_DEF_OCTET_STRING_tags) + / sizeof(asn_DEF_OCTET_STRING_tags[0]), + { 0, 0, asn_generic_no_constraint }, + 0, 0, /* No members */ + &asn_SPC_OCTET_STRING_specs +}; + +#undef _CH_PHASE +#undef NEXT_PHASE +#undef PREV_PHASE +#define _CH_PHASE(ctx, inc) do { \ + if(ctx->phase == 0) \ + ctx->context = 0; \ + ctx->phase += inc; \ + } while(0) +#define NEXT_PHASE(ctx) _CH_PHASE(ctx, +1) +#define PREV_PHASE(ctx) _CH_PHASE(ctx, -1) + +#undef ADVANCE +#define ADVANCE(num_bytes) do { \ + size_t num = (num_bytes); \ + buf_ptr = ((const char *)buf_ptr) + num; \ + size -= num; \ + consumed_myself += num; \ + } while(0) + +#undef RETURN +#define RETURN(_code) do { \ + asn_dec_rval_t tmprval; \ + tmprval.code = _code; \ + tmprval.consumed = consumed_myself; \ + return tmprval; \ + } while(0) + +#undef APPEND +#define APPEND(bufptr, bufsize) do { \ + size_t _bs = (bufsize); /* Append size */ \ + size_t _ns = ctx->context; /* Allocated now */ \ + size_t _es = st->size + _bs; /* Expected size */ \ + /* int is really a typeof(st->size): */ \ + if((int)_es < 0) RETURN(RC_FAIL); \ + if(_ns <= _es) { \ + void *ptr; \ + /* Be nice and round to the memory allocator */ \ + do { _ns = _ns ? _ns << 1 : 16; } \ + while(_ns <= _es); \ + /* int is really a typeof(st->size): */ \ + if((int)_ns < 0) RETURN(RC_FAIL); \ + ptr = REALLOC(st->buf, _ns); \ + if(ptr) { \ + st->buf = (uint8_t *)ptr; \ + ctx->context = _ns; \ + } else { \ + RETURN(RC_FAIL); \ + } \ + ASN_DEBUG("Reallocating into %ld", (long)_ns); \ + } \ + memcpy(st->buf + st->size, bufptr, _bs); \ + /* Convenient nul-termination */ \ + st->buf[_es] = '\0'; \ + st->size = _es; \ + } while(0) + +/* + * The main reason why ASN.1 is still alive is that too much time and effort + * is necessary for learning it more or less adequately, thus creating a gut + * necessity to demonstrate that aquired skill everywhere afterwards. + * No, I am not going to explain what the following stuff is. + */ +struct _stack_el { + ber_tlv_len_t left; /* What's left to read (or -1) */ + ber_tlv_len_t got; /* What was actually processed */ + unsigned cont_level; /* Depth of subcontainment */ + int want_nulls; /* Want null "end of content" octets? */ + int bits_chopped; /* Flag in BIT STRING mode */ + ber_tlv_tag_t tag; /* For debugging purposes */ + struct _stack_el *prev; + struct _stack_el *next; +}; +struct _stack { + struct _stack_el *tail; + struct _stack_el *cur_ptr; +}; + +static struct _stack_el * +OS__add_stack_el(struct _stack *st) { + struct _stack_el *nel; + + /* + * Reuse the old stack frame or allocate a new one. + */ + if(st->cur_ptr && st->cur_ptr->next) { + nel = st->cur_ptr->next; + nel->bits_chopped = 0; + nel->got = 0; + /* Retain the nel->cont_level, it's correct. */ + } else { + nel = (struct _stack_el *)CALLOC(1, sizeof(struct _stack_el)); + if(nel == NULL) + return NULL; + + if(st->tail) { + /* Increase a subcontainment depth */ + nel->cont_level = st->tail->cont_level + 1; + st->tail->next = nel; + } + nel->prev = st->tail; + st->tail = nel; + } + + st->cur_ptr = nel; + + return nel; +} + +static struct _stack * +_new_stack(void) { + return (struct _stack *)CALLOC(1, sizeof(struct _stack)); +} + +/* + * Decode OCTET STRING type. + */ +asn_dec_rval_t +OCTET_STRING_decode_ber(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, void **sptr, + const void *buf_ptr, size_t size, int tag_mode) { + const asn_OCTET_STRING_specifics_t *specs = td->specifics + ? (const asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_SPC_OCTET_STRING_specs; + BIT_STRING_t *st = (BIT_STRING_t *)*sptr; + asn_dec_rval_t rval; + asn_struct_ctx_t *ctx; + ssize_t consumed_myself = 0; + struct _stack *stck; /* Expectations stack structure */ + struct _stack_el *sel = 0; /* Stack element */ + int tlv_constr; + enum asn_OS_Subvariant type_variant = specs->subvariant; + + ASN_DEBUG("Decoding %s as %s (frame %ld)", + td->name, + (type_variant == ASN_OSUBV_STR) ? + "OCTET STRING" : "OS-SpecialCase", + (long)size); + + /* + * Create the string if does not exist. + */ + if(st == NULL) { + st = (BIT_STRING_t *)(*sptr = CALLOC(1, specs->struct_size)); + if(st == NULL) RETURN(RC_FAIL); + } + + /* Restore parsing context */ + ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); + + switch(ctx->phase) { + case 0: + /* + * Check tags. + */ + rval = ber_check_tags(opt_codec_ctx, td, ctx, + buf_ptr, size, tag_mode, -1, + &ctx->left, &tlv_constr); + if(rval.code != RC_OK) + return rval; + + if(tlv_constr) { + /* + * Complex operation, requires stack of expectations. + */ + ctx->ptr = _new_stack(); + if(!ctx->ptr) { + RETURN(RC_FAIL); + } + } else { + /* + * Jump into stackless primitive decoding. + */ + _CH_PHASE(ctx, 3); + if(type_variant == ASN_OSUBV_ANY && tag_mode != 1) + APPEND(buf_ptr, rval.consumed); + ADVANCE(rval.consumed); + goto phase3; + } + + NEXT_PHASE(ctx); + /* Fall through */ + case 1: + phase1: + /* + * Fill the stack with expectations. + */ + stck = (struct _stack *)ctx->ptr; + sel = stck->cur_ptr; + do { + ber_tlv_tag_t tlv_tag; + ber_tlv_len_t tlv_len; + ber_tlv_tag_t expected_tag; + ssize_t tl, ll, tlvl; + /* This one works even if (sel->left == -1) */ + size_t Left = ((!sel||(size_t)sel->left >= size) + ?size:(size_t)sel->left); + + + ASN_DEBUG("%p, s->l=%ld, s->wn=%ld, s->g=%ld\n", (void *)sel, + (long)(sel?sel->left:0), + (long)(sel?sel->want_nulls:0), + (long)(sel?sel->got:0) + ); + if(sel && sel->left <= 0 && sel->want_nulls == 0) { + if(sel->prev) { + struct _stack_el *prev = sel->prev; + if(prev->left != -1) { + if(prev->left < sel->got) + RETURN(RC_FAIL); + prev->left -= sel->got; + } + prev->got += sel->got; + sel = stck->cur_ptr = prev; + if(!sel) break; + tlv_constr = 1; + continue; + } else { + sel = stck->cur_ptr = 0; + break; /* Nothing to wait */ + } + } + + tl = ber_fetch_tag(buf_ptr, Left, &tlv_tag); + ASN_DEBUG("fetch tag(size=%ld,L=%ld), %sstack, left=%ld, wn=%ld, tl=%ld", + (long)size, (long)Left, sel?"":"!", + (long)(sel?sel->left:0), + (long)(sel?sel->want_nulls:0), + (long)tl); + switch(tl) { + case -1: RETURN(RC_FAIL); + case 0: RETURN(RC_WMORE); + } + + tlv_constr = BER_TLV_CONSTRUCTED(buf_ptr); + + ll = ber_fetch_length(tlv_constr, + (const char *)buf_ptr + tl,Left - tl,&tlv_len); + ASN_DEBUG("Got tag=%s, tc=%d, left=%ld, tl=%ld, len=%ld, ll=%ld", + ber_tlv_tag_string(tlv_tag), tlv_constr, + (long)Left, (long)tl, (long)tlv_len, (long)ll); + switch(ll) { + case -1: RETURN(RC_FAIL); + case 0: RETURN(RC_WMORE); + } + + if(sel && sel->want_nulls + && ((const uint8_t *)buf_ptr)[0] == 0 + && ((const uint8_t *)buf_ptr)[1] == 0) + { + + ASN_DEBUG("Eat EOC; wn=%d--", sel->want_nulls); + + if(type_variant == ASN_OSUBV_ANY + && (tag_mode != 1 || sel->cont_level)) + APPEND("\0\0", 2); + + ADVANCE(2); + sel->got += 2; + if(sel->left != -1) { + sel->left -= 2; /* assert(sel->left >= 2) */ + } + + sel->want_nulls--; + if(sel->want_nulls == 0) { + /* Move to the next expectation */ + sel->left = 0; + tlv_constr = 1; + } + + continue; + } + + /* + * Set up expected tags, + * depending on ASN.1 type being decoded. + */ + switch(type_variant) { + case ASN_OSUBV_BIT: + /* X.690: 8.6.4.1, NOTE 2 */ + /* Fall through */ + case ASN_OSUBV_STR: + default: + if(sel) { + unsigned level = sel->cont_level; + if(level < td->all_tags_count) { + expected_tag = td->all_tags[level]; + break; + } else if(td->all_tags_count) { + expected_tag = td->all_tags + [td->all_tags_count - 1]; + break; + } + /* else, Fall through */ + } + /* Fall through */ + case ASN_OSUBV_ANY: + expected_tag = tlv_tag; + break; + } + + + if(tlv_tag != expected_tag) { + char buf[2][32]; + ber_tlv_tag_snprint(tlv_tag, + buf[0], sizeof(buf[0])); + ber_tlv_tag_snprint(td->tags[td->tags_count-1], + buf[1], sizeof(buf[1])); + ASN_DEBUG("Tag does not match expectation: %s != %s", + buf[0], buf[1]); + RETURN(RC_FAIL); + } + + tlvl = tl + ll; /* Combined length of T and L encoding */ + if((tlv_len + tlvl) < 0) { + /* tlv_len value is too big */ + ASN_DEBUG("TLV encoding + length (%ld) is too big", + (long)tlv_len); + RETURN(RC_FAIL); + } + + /* + * Append a new expectation. + */ + sel = OS__add_stack_el(stck); + if(!sel) RETURN(RC_FAIL); + + sel->tag = tlv_tag; + + sel->want_nulls = (tlv_len==-1); + if(sel->prev && sel->prev->left != -1) { + /* Check that the parent frame is big enough */ + if(sel->prev->left < tlvl + (tlv_len==-1?0:tlv_len)) + RETURN(RC_FAIL); + if(tlv_len == -1) + sel->left = sel->prev->left - tlvl; + else + sel->left = tlv_len; + } else { + sel->left = tlv_len; + } + if(type_variant == ASN_OSUBV_ANY + && (tag_mode != 1 || sel->cont_level)) + APPEND(buf_ptr, tlvl); + sel->got += tlvl; + ADVANCE(tlvl); + + ASN_DEBUG("+EXPECT2 got=%ld left=%ld, wn=%d, clvl=%u", + (long)sel->got, (long)sel->left, + sel->want_nulls, sel->cont_level); + + } while(tlv_constr); + if(sel == NULL) { + /* Finished operation, "phase out" */ + ASN_DEBUG("Phase out"); + _CH_PHASE(ctx, +3); + break; + } + + NEXT_PHASE(ctx); + /* Fall through */ + case 2: + stck = (struct _stack *)ctx->ptr; + sel = stck->cur_ptr; + ASN_DEBUG("Phase 2: Need %ld bytes, size=%ld, alrg=%ld, wn=%d", + (long)sel->left, (long)size, (long)sel->got, + sel->want_nulls); + { + ber_tlv_len_t len; + + assert(sel->left >= 0); + + len = ((ber_tlv_len_t)size < sel->left) + ? (ber_tlv_len_t)size : sel->left; + if(len > 0) { + if(type_variant == ASN_OSUBV_BIT + && sel->bits_chopped == 0) { + /* Put the unused-bits-octet away */ + st->bits_unused = *(const uint8_t *)buf_ptr; + APPEND(((const char *)buf_ptr+1), (len - 1)); + sel->bits_chopped = 1; + } else { + APPEND(buf_ptr, len); + } + ADVANCE(len); + sel->left -= len; + sel->got += len; + } + + if(sel->left) { + ASN_DEBUG("OS left %ld, size = %ld, wn=%d\n", + (long)sel->left, (long)size, sel->want_nulls); + RETURN(RC_WMORE); + } + + PREV_PHASE(ctx); + goto phase1; + } + break; + case 3: + phase3: + /* + * Primitive form, no stack required. + */ + assert(ctx->left >= 0); + + if(size < (size_t)ctx->left) { + if(!size) RETURN(RC_WMORE); + if(type_variant == ASN_OSUBV_BIT && !ctx->context) { + st->bits_unused = *(const uint8_t *)buf_ptr; + ctx->left--; + ADVANCE(1); + } + APPEND(buf_ptr, size); + assert(ctx->context > 0); + ctx->left -= size; + ADVANCE(size); + RETURN(RC_WMORE); + } else { + if(type_variant == ASN_OSUBV_BIT + && !ctx->context && ctx->left) { + st->bits_unused = *(const uint8_t *)buf_ptr; + ctx->left--; + ADVANCE(1); + } + APPEND(buf_ptr, ctx->left); + ADVANCE(ctx->left); + ctx->left = 0; + + NEXT_PHASE(ctx); + } + break; + } + + if(sel) { + ASN_DEBUG("3sel p=%p, wn=%d, l=%ld, g=%ld, size=%ld", + (void *)sel->prev, sel->want_nulls, + (long)sel->left, (long)sel->got, (long)size); + if(sel->prev || sel->want_nulls > 1 || sel->left > 0) { + RETURN(RC_WMORE); + } + } + + /* + * BIT STRING-specific processing. + */ + if(type_variant == ASN_OSUBV_BIT) { + if(st->size) { + if(st->bits_unused < 0 || st->bits_unused > 7) { + RETURN(RC_FAIL); + } + /* Finalize BIT STRING: zero out unused bits. */ + st->buf[st->size-1] &= 0xff << st->bits_unused; + } else { + if(st->bits_unused) { + RETURN(RC_FAIL); + } + } + } + + ASN_DEBUG("Took %ld bytes to encode %s: [%s]:%ld", + (long)consumed_myself, td->name, + (type_variant == ASN_OSUBV_STR) ? (char *)st->buf : "", + (long)st->size); + + + RETURN(RC_OK); +} + +/* + * Encode OCTET STRING type using DER. + */ +asn_enc_rval_t +OCTET_STRING_encode_der(const asn_TYPE_descriptor_t *td, const void *sptr, + int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_enc_rval_t er; + const asn_OCTET_STRING_specifics_t *specs = td->specifics + ? (const asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_SPC_OCTET_STRING_specs; + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + enum asn_OS_Subvariant type_variant = specs->subvariant; + int fix_last_byte = 0; + + ASN_DEBUG("%s %s as OCTET STRING", + cb?"Estimating":"Encoding", td->name); + + /* + * Write tags. + */ + if(type_variant != ASN_OSUBV_ANY || tag_mode == 1) { + er.encoded = der_write_tags(td, + (type_variant == ASN_OSUBV_BIT) + st->size, + tag_mode, type_variant == ASN_OSUBV_ANY, tag, + cb, app_key); + if(er.encoded == -1) { + er.failed_type = td; + er.structure_ptr = sptr; + return er; + } + } else { + /* Disallow: [] IMPLICIT ANY */ + assert(type_variant != ASN_OSUBV_ANY || tag_mode != -1); + er.encoded = 0; + } + + if(!cb) { + er.encoded += (type_variant == ASN_OSUBV_BIT) + st->size; + ASN__ENCODED_OK(er); + } + + /* + * Prepare to deal with the last octet of BIT STRING. + */ + if(type_variant == ASN_OSUBV_BIT) { + uint8_t b = st->bits_unused & 0x07; + if(b && st->size) fix_last_byte = 1; + ASN__CALLBACK(&b, 1); + } + + /* Invoke callback for the main part of the buffer */ + ASN__CALLBACK(st->buf, st->size - fix_last_byte); + + /* The last octet should be stripped off the unused bits */ + if(fix_last_byte) { + uint8_t b = st->buf[st->size-1] & (0xff << st->bits_unused); + ASN__CALLBACK(&b, 1); + } + + ASN__ENCODED_OK(er); +cb_failed: + ASN__ENCODE_FAILED; +} + +asn_enc_rval_t +OCTET_STRING_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + const char * const h2c = "0123456789ABCDEF"; + const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; + asn_enc_rval_t er; + char scratch[16 * 3 + 4]; + char *p = scratch; + uint8_t *buf; + uint8_t *end; + size_t i; + + if(!st || (!st->buf && st->size)) + ASN__ENCODE_FAILED; + + er.encoded = 0; + + /* + * Dump the contents of the buffer in hexadecimal. + */ + buf = st->buf; + end = buf + st->size; + if(flags & XER_F_CANONICAL) { + char *scend = scratch + (sizeof(scratch) - 2); + for(; buf < end; buf++) { + if(p >= scend) { + ASN__CALLBACK(scratch, p - scratch); + p = scratch; + } + *p++ = h2c[(*buf >> 4) & 0x0F]; + *p++ = h2c[*buf & 0x0F]; + } + + ASN__CALLBACK(scratch, p-scratch); /* Dump the rest */ + } else { + for(i = 0; buf < end; buf++, i++) { + if(!(i % 16) && (i || st->size > 16)) { + ASN__CALLBACK(scratch, p-scratch); + p = scratch; + ASN__TEXT_INDENT(1, ilevel); + } + *p++ = h2c[(*buf >> 4) & 0x0F]; + *p++ = h2c[*buf & 0x0F]; + *p++ = 0x20; + } + if(p - scratch) { + p--; /* Remove the tail space */ + ASN__CALLBACK(scratch, p-scratch); /* Dump the rest */ + if(st->size > 16) + ASN__TEXT_INDENT(1, ilevel-1); + } + } + + ASN__ENCODED_OK(er); +cb_failed: + ASN__ENCODE_FAILED; +} + +static const struct OCTET_STRING__xer_escape_table_s { + const char *string; + int size; +} OCTET_STRING__xer_escape_table[] = { +#define OSXET(s) { s, sizeof(s) - 1 } + OSXET("\074\156\165\154\057\076"), /* */ + OSXET("\074\163\157\150\057\076"), /* */ + OSXET("\074\163\164\170\057\076"), /* */ + OSXET("\074\145\164\170\057\076"), /* */ + OSXET("\074\145\157\164\057\076"), /* */ + OSXET("\074\145\156\161\057\076"), /* */ + OSXET("\074\141\143\153\057\076"), /* */ + OSXET("\074\142\145\154\057\076"), /* */ + OSXET("\074\142\163\057\076"), /* */ + OSXET("\011"), /* \t */ + OSXET("\012"), /* \n */ + OSXET("\074\166\164\057\076"), /* */ + OSXET("\074\146\146\057\076"), /* */ + OSXET("\015"), /* \r */ + OSXET("\074\163\157\057\076"), /* */ + OSXET("\074\163\151\057\076"), /* */ + OSXET("\074\144\154\145\057\076"), /* */ + OSXET("\074\144\143\061\057\076"), /* */ + OSXET("\074\144\143\062\057\076"), /* */ + OSXET("\074\144\143\063\057\076"), /* */ + OSXET("\074\144\143\064\057\076"), /* */ + OSXET("\074\156\141\153\057\076"), /* */ + OSXET("\074\163\171\156\057\076"), /* */ + OSXET("\074\145\164\142\057\076"), /* */ + OSXET("\074\143\141\156\057\076"), /* */ + OSXET("\074\145\155\057\076"), /* */ + OSXET("\074\163\165\142\057\076"), /* */ + OSXET("\074\145\163\143\057\076"), /* */ + OSXET("\074\151\163\064\057\076"), /* */ + OSXET("\074\151\163\063\057\076"), /* */ + OSXET("\074\151\163\062\057\076"), /* */ + OSXET("\074\151\163\061\057\076"), /* */ + { 0, 0 }, /* " " */ + { 0, 0 }, /* ! */ + { 0, 0 }, /* \" */ + { 0, 0 }, /* # */ + { 0, 0 }, /* $ */ + { 0, 0 }, /* % */ + OSXET("\046\141\155\160\073"), /* & */ + { 0, 0 }, /* ' */ + {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, /* ()*+,-./ */ + {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, /* 01234567 */ + {0,0},{0,0},{0,0},{0,0}, /* 89:; */ + OSXET("\046\154\164\073"), /* < */ + { 0, 0 }, /* = */ + OSXET("\046\147\164\073"), /* > */ +}; + +static int +OS__check_escaped_control_char(const void *buf, int size) { + size_t i; + /* + * Inefficient algorithm which translates the escape sequences + * defined above into characters. Returns -1 if not found. + * TODO: replace by a faster algorithm (bsearch(), hash or + * nested table lookups). + */ + for(i = 0; i < 32 /* Don't spend time on the bottom half */; i++) { + const struct OCTET_STRING__xer_escape_table_s *el; + el = &OCTET_STRING__xer_escape_table[i]; + if(el->size == size && memcmp(buf, el->string, size) == 0) + return i; + } + return -1; +} + +static int +OCTET_STRING__handle_control_chars(void *struct_ptr, const void *chunk_buf, size_t chunk_size) { + /* + * This might be one of the escape sequences + * for control characters. Check it out. + * #11.15.5 + */ + int control_char = OS__check_escaped_control_char(chunk_buf,chunk_size); + if(control_char >= 0) { + OCTET_STRING_t *st = (OCTET_STRING_t *)struct_ptr; + void *p = REALLOC(st->buf, st->size + 2); + if(p) { + st->buf = (uint8_t *)p; + st->buf[st->size++] = control_char; + st->buf[st->size] = '\0'; /* nul-termination */ + return 0; + } + } + + return -1; /* No, it's not */ +} + +asn_enc_rval_t +OCTET_STRING_encode_xer_utf8(const asn_TYPE_descriptor_t *td, const void *sptr, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; + asn_enc_rval_t er; + uint8_t *buf, *end; + uint8_t *ss; /* Sequence start */ + ssize_t encoded_len = 0; + + (void)ilevel; /* Unused argument */ + (void)flags; /* Unused argument */ + + if(!st || (!st->buf && st->size)) + ASN__ENCODE_FAILED; + + buf = st->buf; + end = buf + st->size; + for(ss = buf; buf < end; buf++) { + unsigned int ch = *buf; + int s_len; /* Special encoding sequence length */ + + /* + * Escape certain characters: X.680/11.15 + */ + if(ch < sizeof(OCTET_STRING__xer_escape_table) + /sizeof(OCTET_STRING__xer_escape_table[0]) + && (s_len = OCTET_STRING__xer_escape_table[ch].size)) { + if(((buf - ss) && cb(ss, buf - ss, app_key) < 0) + || cb(OCTET_STRING__xer_escape_table[ch].string, s_len, + app_key) < 0) + ASN__ENCODE_FAILED; + encoded_len += (buf - ss) + s_len; + ss = buf + 1; + } + } + + encoded_len += (buf - ss); + if((buf - ss) && cb(ss, buf - ss, app_key) < 0) + ASN__ENCODE_FAILED; + + er.encoded = encoded_len; + ASN__ENCODED_OK(er); +} + +/* + * Convert from hexadecimal format (cstring): "AB CD EF" + */ +static ssize_t OCTET_STRING__convert_hexadecimal(void *sptr, const void *chunk_buf, size_t chunk_size, int have_more) { + OCTET_STRING_t *st = (OCTET_STRING_t *)sptr; + const char *chunk_stop = (const char *)chunk_buf; + const char *p = chunk_stop; + const char *pend = p + chunk_size; + unsigned int clv = 0; + int half = 0; /* Half bit */ + uint8_t *buf; + + /* Reallocate buffer according to high cap estimation */ + size_t new_size = st->size + (chunk_size + 1) / 2; + void *nptr = REALLOC(st->buf, new_size + 1); + if(!nptr) return -1; + st->buf = (uint8_t *)nptr; + buf = st->buf + st->size; + + /* + * If something like " a b c " appears here, the " a b":3 will be + * converted, and the rest skipped. That is, unless buf_size is greater + * than chunk_size, then it'll be equivalent to "ABC0". + */ + for(; p < pend; p++) { + int ch = *(const unsigned char *)p; + switch(ch) { + case 0x09: case 0x0a: case 0x0c: case 0x0d: + case 0x20: + /* Ignore whitespace */ + continue; + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: /*01234*/ + case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: /*56789*/ + clv = (clv << 4) + (ch - 0x30); + break; + case 0x41: case 0x42: case 0x43: /* ABC */ + case 0x44: case 0x45: case 0x46: /* DEF */ + clv = (clv << 4) + (ch - 0x41 + 10); + break; + case 0x61: case 0x62: case 0x63: /* abc */ + case 0x64: case 0x65: case 0x66: /* def */ + clv = (clv << 4) + (ch - 0x61 + 10); + break; + default: + *buf = 0; /* JIC */ + return -1; + } + if(half++) { + half = 0; + *buf++ = clv; + chunk_stop = p + 1; + } + } + + /* + * Check partial decoding. + */ + if(half) { + if(have_more) { + /* + * Partial specification is fine, + * because no more more PXER_TEXT data is available. + */ + *buf++ = clv << 4; + chunk_stop = p; + } + } else { + chunk_stop = p; + } + + st->size = buf - st->buf; /* Adjust the buffer size */ + assert(st->size <= new_size); + st->buf[st->size] = 0; /* Courtesy termination */ + + return (chunk_stop - (const char *)chunk_buf); /* Converted size */ +} + +/* + * Convert from binary format: "00101011101" + */ +static ssize_t OCTET_STRING__convert_binary(void *sptr, const void *chunk_buf, size_t chunk_size, int have_more) { + BIT_STRING_t *st = (BIT_STRING_t *)sptr; + const char *p = (const char *)chunk_buf; + const char *pend = p + chunk_size; + int bits_unused = st->bits_unused & 0x7; + uint8_t *buf; + + /* Reallocate buffer according to high cap estimation */ + size_t new_size = st->size + (chunk_size + 7) / 8; + void *nptr = REALLOC(st->buf, new_size + 1); + if(!nptr) return -1; + st->buf = (uint8_t *)nptr; + buf = st->buf + st->size; + + (void)have_more; + + if(bits_unused == 0) + bits_unused = 8; + else if(st->size) + buf--; + + /* + * Convert series of 0 and 1 into the octet string. + */ + for(; p < pend; p++) { + int ch = *(const unsigned char *)p; + switch(ch) { + case 0x09: case 0x0a: case 0x0c: case 0x0d: + case 0x20: + /* Ignore whitespace */ + break; + case 0x30: + case 0x31: + if(bits_unused-- <= 0) { + *++buf = 0; /* Clean the cell */ + bits_unused = 7; + } + *buf |= (ch&1) << bits_unused; + break; + default: + st->bits_unused = bits_unused; + return -1; + } + } + + if(bits_unused == 8) { + st->size = buf - st->buf; + st->bits_unused = 0; + } else { + st->size = buf - st->buf + 1; + st->bits_unused = bits_unused; + } + + assert(st->size <= new_size); + st->buf[st->size] = 0; /* Courtesy termination */ + + return chunk_size; /* Converted in full */ +} + +/* + * Something like strtod(), but with stricter rules. + */ +static int +OS__strtoent(int base, const char *buf, const char *end, int32_t *ret_value) { + const int32_t last_unicode_codepoint = 0x10ffff; + int32_t val = 0; + const char *p; + + for(p = buf; p < end; p++) { + int ch = *p; + + switch(ch) { + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: /*01234*/ + case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: /*56789*/ + val = val * base + (ch - 0x30); + break; + case 0x41: case 0x42: case 0x43: /* ABC */ + case 0x44: case 0x45: case 0x46: /* DEF */ + val = val * base + (ch - 0x41 + 10); + break; + case 0x61: case 0x62: case 0x63: /* abc */ + case 0x64: case 0x65: case 0x66: /* def */ + val = val * base + (ch - 0x61 + 10); + break; + case 0x3b: /* ';' */ + *ret_value = val; + return (p - buf) + 1; + default: + return -1; /* Character set error */ + } + + /* Value exceeds the Unicode range. */ + if(val > last_unicode_codepoint) { + return -1; + } + } + + *ret_value = -1; + return (p - buf); +} + +/* + * Convert from the plain UTF-8 format, expanding entity references: "2 < 3" + */ +static ssize_t +OCTET_STRING__convert_entrefs(void *sptr, const void *chunk_buf, + size_t chunk_size, int have_more) { + OCTET_STRING_t *st = (OCTET_STRING_t *)sptr; + const char *p = (const char *)chunk_buf; + const char *pend = p + chunk_size; + uint8_t *buf; + + /* Reallocate buffer */ + size_t new_size = st->size + chunk_size; + void *nptr = REALLOC(st->buf, new_size + 1); + if(!nptr) return -1; + st->buf = (uint8_t *)nptr; + buf = st->buf + st->size; + + /* + * Convert series of 0 and 1 into the octet string. + */ + for(; p < pend; p++) { + int ch = *(const unsigned char *)p; + int len; /* Length of the rest of the chunk */ + + if(ch != 0x26 /* '&' */) { + *buf++ = ch; + continue; /* That was easy... */ + } + + /* + * Process entity reference. + */ + len = chunk_size - (p - (const char *)chunk_buf); + if(len == 1 /* "&" */) goto want_more; + if(p[1] == 0x23 /* '#' */) { + const char *pval; /* Pointer to start of digits */ + int32_t val = 0; /* Entity reference value */ + int base; + + if(len == 2 /* "&#" */) goto want_more; + if(p[2] == 0x78 /* 'x' */) + pval = p + 3, base = 16; + else + pval = p + 2, base = 10; + len = OS__strtoent(base, pval, p + len, &val); + if(len == -1) { + /* Invalid charset. Just copy verbatim. */ + *buf++ = ch; + continue; + } + if(!len || pval[len-1] != 0x3b) goto want_more; + assert(val > 0); + p += (pval - p) + len - 1; /* Advance past entref */ + + if(val < 0x80) { + *buf++ = (char)val; + } else if(val < 0x800) { + *buf++ = 0xc0 | ((val >> 6)); + *buf++ = 0x80 | ((val & 0x3f)); + } else if(val < 0x10000) { + *buf++ = 0xe0 | ((val >> 12)); + *buf++ = 0x80 | ((val >> 6) & 0x3f); + *buf++ = 0x80 | ((val & 0x3f)); + } else if(val < 0x200000) { + *buf++ = 0xf0 | ((val >> 18)); + *buf++ = 0x80 | ((val >> 12) & 0x3f); + *buf++ = 0x80 | ((val >> 6) & 0x3f); + *buf++ = 0x80 | ((val & 0x3f)); + } else if(val < 0x4000000) { + *buf++ = 0xf8 | ((val >> 24)); + *buf++ = 0x80 | ((val >> 18) & 0x3f); + *buf++ = 0x80 | ((val >> 12) & 0x3f); + *buf++ = 0x80 | ((val >> 6) & 0x3f); + *buf++ = 0x80 | ((val & 0x3f)); + } else { + *buf++ = 0xfc | ((val >> 30) & 0x1); + *buf++ = 0x80 | ((val >> 24) & 0x3f); + *buf++ = 0x80 | ((val >> 18) & 0x3f); + *buf++ = 0x80 | ((val >> 12) & 0x3f); + *buf++ = 0x80 | ((val >> 6) & 0x3f); + *buf++ = 0x80 | ((val & 0x3f)); + } + } else { + /* + * Ugly, limited parsing of & > < + */ + char *sc = (char *)memchr(p, 0x3b, len > 5 ? 5 : len); + if(!sc) goto want_more; + if((sc - p) == 4 + && p[1] == 0x61 /* 'a' */ + && p[2] == 0x6d /* 'm' */ + && p[3] == 0x70 /* 'p' */) { + *buf++ = 0x26; + p = sc; + continue; + } + if((sc - p) == 3) { + if(p[1] == 0x6c) { + *buf = 0x3c; /* '<' */ + } else if(p[1] == 0x67) { + *buf = 0x3e; /* '>' */ + } else { + /* Unsupported entity reference */ + *buf++ = ch; + continue; + } + if(p[2] != 0x74) { + /* Unsupported entity reference */ + *buf++ = ch; + continue; + } + buf++; + p = sc; + continue; + } + /* Unsupported entity reference */ + *buf++ = ch; + } + + continue; + want_more: + if(have_more) { + /* + * We know that no more data (of the same type) + * is coming. Copy the rest verbatim. + */ + *buf++ = ch; + continue; + } + chunk_size = (p - (const char *)chunk_buf); + /* Processing stalled: need more data */ + break; + } + + st->size = buf - st->buf; + assert(st->size <= new_size); + st->buf[st->size] = 0; /* Courtesy termination */ + + return chunk_size; /* Converted in full */ +} + +/* + * Decode OCTET STRING from the XML element's body. + */ +static asn_dec_rval_t +OCTET_STRING__decode_xer( + const asn_codec_ctx_t *opt_codec_ctx, const asn_TYPE_descriptor_t *td, + void **sptr, const char *opt_mname, const void *buf_ptr, size_t size, + int (*opt_unexpected_tag_decoder)(void *struct_ptr, const void *chunk_buf, + size_t chunk_size), + ssize_t (*body_receiver)(void *struct_ptr, const void *chunk_buf, + size_t chunk_size, int have_more)) { + OCTET_STRING_t *st = (OCTET_STRING_t *)*sptr; + const asn_OCTET_STRING_specifics_t *specs = td->specifics + ? (const asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_SPC_OCTET_STRING_specs; + const char *xml_tag = opt_mname ? opt_mname : td->xml_tag; + asn_struct_ctx_t *ctx; /* Per-structure parser context */ + asn_dec_rval_t rval; /* Return value from the decoder */ + int st_allocated; + + /* + * Create the string if does not exist. + */ + if(!st) { + st = (OCTET_STRING_t *)CALLOC(1, specs->struct_size); + *sptr = (void *)st; + if(!st) goto sta_failed; + st_allocated = 1; + } else { + st_allocated = 0; + } + if(!st->buf) { + /* This is separate from above section */ + st->buf = (uint8_t *)CALLOC(1, 1); + if(!st->buf) { + if(st_allocated) { + *sptr = 0; + goto stb_failed; + } else { + goto sta_failed; + } + } + } + + /* Restore parsing context */ + ctx = (asn_struct_ctx_t *)(((char *)*sptr) + specs->ctx_offset); + + return xer_decode_general(opt_codec_ctx, ctx, *sptr, xml_tag, + buf_ptr, size, opt_unexpected_tag_decoder, body_receiver); + +stb_failed: + FREEMEM(st); +sta_failed: + rval.code = RC_FAIL; + rval.consumed = 0; + return rval; +} + +/* + * Decode OCTET STRING from the hexadecimal data. + */ +asn_dec_rval_t +OCTET_STRING_decode_xer_hex(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, void **sptr, + const char *opt_mname, const void *buf_ptr, + size_t size) { + return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname, + buf_ptr, size, 0, OCTET_STRING__convert_hexadecimal); +} + +/* + * Decode OCTET STRING from the binary (0/1) data. + */ +asn_dec_rval_t +OCTET_STRING_decode_xer_binary(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, void **sptr, + const char *opt_mname, const void *buf_ptr, + size_t size) { + return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname, + buf_ptr, size, 0, OCTET_STRING__convert_binary); +} + +/* + * Decode OCTET STRING from the string (ASCII/UTF-8) data. + */ +asn_dec_rval_t +OCTET_STRING_decode_xer_utf8(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, void **sptr, + const char *opt_mname, const void *buf_ptr, + size_t size) { + return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname, + buf_ptr, size, + OCTET_STRING__handle_control_chars, + OCTET_STRING__convert_entrefs); +} + +#ifndef ASN_DISABLE_PER_SUPPORT + +static int +OCTET_STRING_per_get_characters(asn_per_data_t *po, uint8_t *buf, + size_t units, unsigned int bpc, unsigned int unit_bits, + long lb, long ub, const asn_per_constraints_t *pc) { + uint8_t *end = buf + units * bpc; + + ASN_DEBUG("Expanding %d characters into (%ld..%ld):%d", + (int)units, lb, ub, unit_bits); + + /* X.691: 27.5.4 */ + if((unsigned long)ub <= ((unsigned long)2 << (unit_bits - 1))) { + /* Decode without translation */ + lb = 0; + } else if(pc && pc->code2value) { + if(unit_bits > 16) + return 1; /* FATAL: can't have constrained + * UniversalString with more than + * 16 million code points */ + for(; buf < end; buf += bpc) { + int value; + int code = per_get_few_bits(po, unit_bits); + if(code < 0) return -1; /* WMORE */ + value = pc->code2value(code); + if(value < 0) { + ASN_DEBUG("Code %d (0x%02x) is" + " not in map (%ld..%ld)", + code, code, lb, ub); + return 1; /* FATAL */ + } + switch(bpc) { + case 1: *buf = value; break; + case 2: buf[0] = value >> 8; buf[1] = value; break; + case 4: buf[0] = value >> 24; buf[1] = value >> 16; + buf[2] = value >> 8; buf[3] = value; break; + } + } + return 0; + } + + /* Shortcut the no-op copying to the aligned structure */ + if(lb == 0 && (unit_bits == 8 * bpc)) { + return per_get_many_bits(po, buf, 0, unit_bits * units); + } + + for(; buf < end; buf += bpc) { + int32_t code = per_get_few_bits(po, unit_bits); + int32_t ch = code + lb; + if(code < 0) return -1; /* WMORE */ + if(ch > ub) { + ASN_DEBUG("Code %d is out of range (%ld..%ld)", + ch, lb, ub); + return 1; /* FATAL */ + } + switch(bpc) { + case 1: *buf = ch; break; + case 2: buf[0] = ch >> 8; buf[1] = ch; break; + case 4: buf[0] = ch >> 24; buf[1] = ch >> 16; + buf[2] = ch >> 8; buf[3] = ch; break; + } + } + + return 0; +} + +static int +OCTET_STRING_per_put_characters(asn_per_outp_t *po, const uint8_t *buf, + size_t units, unsigned int bpc, unsigned int unit_bits, + long lb, long ub, const asn_per_constraints_t *pc) { + const uint8_t *end = buf + units * bpc; + + ASN_DEBUG("Squeezing %d characters into (%ld..%ld):%d (%d bpc)", + (int)units, lb, ub, unit_bits, bpc); + + /* X.691: 27.5.4 */ + if((unsigned long)ub <= ((unsigned long)2 << (unit_bits - 1))) { + /* Encode as is */ + lb = 0; + } else if(pc && pc->value2code) { + for(; buf < end; buf += bpc) { + int code; + uint32_t value; + switch(bpc) { + case 1: value = *(const uint8_t *)buf; break; + case 2: value = (buf[0] << 8) | buf[1]; break; + case 4: value = (buf[0] << 24) | (buf[1] << 16) + | (buf[2] << 8) | buf[3]; break; + default: return -1; + } + code = pc->value2code(value); + if(code < 0) { + ASN_DEBUG("Character %d (0x%02x) is" + " not in map (%ld..%ld)", + *buf, *buf, lb, ub); + return -1; + } + if(per_put_few_bits(po, code, unit_bits)) + return -1; + } + } + + /* Shortcut the no-op copying to the aligned structure */ + if(lb == 0 && (unit_bits == 8 * bpc)) { + return per_put_many_bits(po, buf, unit_bits * units); + } + + for(ub -= lb; buf < end; buf += bpc) { + int ch; + uint32_t value; + switch(bpc) { + case 1: + value = *(const uint8_t *)buf; + break; + case 2: + value = (buf[0] << 8) | buf[1]; + break; + case 4: + value = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + break; + default: + return -1; + } + ch = value - lb; + if(ch < 0 || ch > ub) { + ASN_DEBUG("Character %d (0x%02x) is out of range (%ld..%ld)", *buf, + value, lb, ub + lb); + return -1; + } + if(per_put_few_bits(po, ch, unit_bits)) return -1; + } + + return 0; +} + +static asn_per_constraints_t asn_DEF_OCTET_STRING_constraints = { + { APC_CONSTRAINED, 8, 8, 0, 255 }, + { APC_SEMI_CONSTRAINED, -1, -1, 0, 0 }, + 0, 0 +}; + +asn_dec_rval_t +OCTET_STRING_decode_uper(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, + const asn_per_constraints_t *constraints, void **sptr, + asn_per_data_t *pd) { + const asn_OCTET_STRING_specifics_t *specs = td->specifics + ? (const asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_SPC_OCTET_STRING_specs; + const asn_per_constraints_t *pc = + constraints ? constraints : td->encoding_constraints.per_constraints; + const asn_per_constraint_t *cval; + const asn_per_constraint_t *csiz; + asn_dec_rval_t rval = { RC_OK, 0 }; + OCTET_STRING_t *st = (OCTET_STRING_t *)*sptr; + ssize_t consumed_myself = 0; + int repeat; + enum { + OS__BPC_CHAR = 1, + OS__BPC_U16 = 2, + OS__BPC_U32 = 4 + } bpc; /* Bytes per character */ + unsigned int unit_bits; + unsigned int canonical_unit_bits; + + (void)opt_codec_ctx; + + if(pc) { + cval = &pc->value; + csiz = &pc->size; + } else { + cval = &asn_DEF_OCTET_STRING_constraints.value; + csiz = &asn_DEF_OCTET_STRING_constraints.size; + } + + switch(specs->subvariant) { + default: + case ASN_OSUBV_ANY: + case ASN_OSUBV_BIT: + ASN_DEBUG("Unrecognized subvariant %d", specs->subvariant); + RETURN(RC_FAIL); + break; + case ASN_OSUBV_STR: + canonical_unit_bits = unit_bits = 8; + if(cval->flags & APC_CONSTRAINED) + unit_bits = cval->range_bits; + bpc = OS__BPC_CHAR; + break; + case ASN_OSUBV_U16: + canonical_unit_bits = unit_bits = 16; + if(cval->flags & APC_CONSTRAINED) + unit_bits = cval->range_bits; + bpc = OS__BPC_U16; + break; + case ASN_OSUBV_U32: + canonical_unit_bits = unit_bits = 32; + if(cval->flags & APC_CONSTRAINED) + unit_bits = cval->range_bits; + bpc = OS__BPC_U32; + break; + } + + /* + * Allocate the string. + */ + if(!st) { + st = (OCTET_STRING_t *)(*sptr = CALLOC(1, specs->struct_size)); + if(!st) RETURN(RC_FAIL); + } + + ASN_DEBUG("PER Decoding %s size %ld .. %ld bits %d", + csiz->flags & APC_EXTENSIBLE ? "extensible" : "non-extensible", + csiz->lower_bound, csiz->upper_bound, csiz->effective_bits); + + if(csiz->flags & APC_EXTENSIBLE) { + int inext = per_get_few_bits(pd, 1); + if(inext < 0) RETURN(RC_WMORE); + if(inext) { + csiz = &asn_DEF_OCTET_STRING_constraints.size; + unit_bits = canonical_unit_bits; + } + } + + if(csiz->effective_bits >= 0) { + FREEMEM(st->buf); + if(bpc) { + st->size = csiz->upper_bound * bpc; + } else { + st->size = (csiz->upper_bound + 7) >> 3; + } + st->buf = (uint8_t *)MALLOC(st->size + 1); + if(!st->buf) { st->size = 0; RETURN(RC_FAIL); } + } + + /* X.691, #16.5: zero-length encoding */ + /* X.691, #16.6: short fixed length encoding (up to 2 octets) */ + /* X.691, #16.7: long fixed length encoding (up to 64K octets) */ + if(csiz->effective_bits == 0) { + int ret; + if(bpc) { + ASN_DEBUG("Encoding OCTET STRING size %ld", + csiz->upper_bound); + ret = OCTET_STRING_per_get_characters(pd, st->buf, + csiz->upper_bound, bpc, unit_bits, + cval->lower_bound, cval->upper_bound, pc); + if(ret > 0) RETURN(RC_FAIL); + } else { + ASN_DEBUG("Encoding BIT STRING size %ld", + csiz->upper_bound); + ret = per_get_many_bits(pd, st->buf, 0, + unit_bits * csiz->upper_bound); + } + if(ret < 0) RETURN(RC_WMORE); + consumed_myself += unit_bits * csiz->upper_bound; + st->buf[st->size] = 0; + RETURN(RC_OK); + } + + st->size = 0; + do { + ssize_t raw_len; + ssize_t len_bytes; + void *p; + int ret; + + /* Get the PER length */ + raw_len = uper_get_length(pd, csiz->effective_bits, csiz->lower_bound, + &repeat); + if(raw_len < 0) RETURN(RC_WMORE); + if(raw_len == 0 && st->buf) break; + + ASN_DEBUG("Got PER length eb %ld, len %ld, %s (%s)", + (long)csiz->effective_bits, (long)raw_len, + repeat ? "repeat" : "once", td->name); + len_bytes = raw_len * bpc; + p = REALLOC(st->buf, st->size + len_bytes + 1); + if(!p) RETURN(RC_FAIL); + st->buf = (uint8_t *)p; + + ret = OCTET_STRING_per_get_characters(pd, &st->buf[st->size], raw_len, + bpc, unit_bits, cval->lower_bound, + cval->upper_bound, pc); + if(ret > 0) RETURN(RC_FAIL); + if(ret < 0) RETURN(RC_WMORE); + st->size += len_bytes; + } while(repeat); + st->buf[st->size] = 0; /* nul-terminate */ + + return rval; +} + +asn_enc_rval_t +OCTET_STRING_encode_uper(const asn_TYPE_descriptor_t *td, + const asn_per_constraints_t *constraints, + const void *sptr, asn_per_outp_t *po) { + const asn_OCTET_STRING_specifics_t *specs = td->specifics + ? (const asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_SPC_OCTET_STRING_specs; + const asn_per_constraints_t *pc = constraints ? constraints + : td->encoding_constraints.per_constraints; + const asn_per_constraint_t *cval; + const asn_per_constraint_t *csiz; + const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; + asn_enc_rval_t er = { 0, 0, 0 }; + int inext = 0; /* Lies not within extension root */ + unsigned int unit_bits; + unsigned int canonical_unit_bits; + size_t size_in_units; + const uint8_t *buf; + int ret; + enum { + OS__BPC_CHAR = 1, + OS__BPC_U16 = 2, + OS__BPC_U32 = 4 + } bpc; /* Bytes per character */ + int ct_extensible; + + if(!st || (!st->buf && st->size)) + ASN__ENCODE_FAILED; + + if(pc) { + cval = &pc->value; + csiz = &pc->size; + } else { + cval = &asn_DEF_OCTET_STRING_constraints.value; + csiz = &asn_DEF_OCTET_STRING_constraints.size; + } + ct_extensible = csiz->flags & APC_EXTENSIBLE; + + switch(specs->subvariant) { + default: + case ASN_OSUBV_ANY: + case ASN_OSUBV_BIT: + ASN__ENCODE_FAILED; + case ASN_OSUBV_STR: + canonical_unit_bits = unit_bits = 8; + if(cval->flags & APC_CONSTRAINED) + unit_bits = cval->range_bits; + bpc = OS__BPC_CHAR; + size_in_units = st->size; + break; + case ASN_OSUBV_U16: + canonical_unit_bits = unit_bits = 16; + if(cval->flags & APC_CONSTRAINED) + unit_bits = cval->range_bits; + bpc = OS__BPC_U16; + size_in_units = st->size >> 1; + if(st->size & 1) { + ASN_DEBUG("%s string size is not modulo 2", td->name); + ASN__ENCODE_FAILED; + } + break; + case ASN_OSUBV_U32: + canonical_unit_bits = unit_bits = 32; + if(cval->flags & APC_CONSTRAINED) + unit_bits = cval->range_bits; + bpc = OS__BPC_U32; + size_in_units = st->size >> 2; + if(st->size & 3) { + ASN_DEBUG("%s string size is not modulo 4", td->name); + ASN__ENCODE_FAILED; + } + break; + } + + ASN_DEBUG("Encoding %s into %" ASN_PRI_SIZE " units of %d bits" + " (%ld..%ld, effective %d)%s", + td->name, size_in_units, unit_bits, + csiz->lower_bound, csiz->upper_bound, + csiz->effective_bits, ct_extensible ? " EXT" : ""); + + /* Figure out whether size lies within PER visible constraint */ + + if(csiz->effective_bits >= 0) { + if((ssize_t)size_in_units < csiz->lower_bound + || (ssize_t)size_in_units > csiz->upper_bound) { + if(ct_extensible) { + csiz = &asn_DEF_OCTET_STRING_constraints.size; + unit_bits = canonical_unit_bits; + inext = 1; + } else { + ASN__ENCODE_FAILED; + } + } + } else { + inext = 0; + } + + if(ct_extensible) { + /* Declare whether length is [not] within extension root */ + if(per_put_few_bits(po, inext, 1)) + ASN__ENCODE_FAILED; + } + + if(csiz->effective_bits >= 0 && !inext) { + ASN_DEBUG("Encoding %" ASN_PRI_SIZE " bytes (%ld), length in %d bits", st->size, + size_in_units - csiz->lower_bound, csiz->effective_bits); + ret = per_put_few_bits(po, size_in_units - csiz->lower_bound, + csiz->effective_bits); + if(ret) ASN__ENCODE_FAILED; + ret = OCTET_STRING_per_put_characters(po, st->buf, size_in_units, bpc, + unit_bits, cval->lower_bound, + cval->upper_bound, pc); + if(ret) ASN__ENCODE_FAILED; + ASN__ENCODED_OK(er); + } + + ASN_DEBUG("Encoding %" ASN_PRI_SIZE " bytes", st->size); + + buf = st->buf; + ASN_DEBUG("Encoding %" ASN_PRI_SIZE " in units", size_in_units); + do { + int need_eom = 0; + ssize_t may_save = uper_put_length(po, size_in_units, &need_eom); + if(may_save < 0) ASN__ENCODE_FAILED; + + ASN_DEBUG("Encoding %" ASN_PRI_SSIZE " of %" ASN_PRI_SIZE "%s", may_save, size_in_units, + need_eom ? ",+EOM" : ""); + + ret = OCTET_STRING_per_put_characters(po, buf, may_save, bpc, unit_bits, + cval->lower_bound, + cval->upper_bound, pc); + if(ret) ASN__ENCODE_FAILED; + + buf += may_save * bpc; + size_in_units -= may_save; + assert(!(may_save & 0x07) || !size_in_units); + if(need_eom && uper_put_length(po, 0, 0)) + ASN__ENCODE_FAILED; /* End of Message length */ + } while(size_in_units); + + ASN__ENCODED_OK(er); +} + +#endif /* ASN_DISABLE_PER_SUPPORT */ + +int +OCTET_STRING_print(const asn_TYPE_descriptor_t *td, const void *sptr, + int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { + const char * const h2c = "0123456789ABCDEF"; + const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; + char scratch[16 * 3 + 4]; + char *p = scratch; + uint8_t *buf; + uint8_t *end; + size_t i; + + (void)td; /* Unused argument */ + + if(!st || (!st->buf && st->size)) + return (cb("", 8, app_key) < 0) ? -1 : 0; + + /* + * Dump the contents of the buffer in hexadecimal. + */ + buf = st->buf; + end = buf + st->size; + for(i = 0; buf < end; buf++, i++) { + if(!(i % 16) && (i || st->size > 16)) { + if(cb(scratch, p - scratch, app_key) < 0) + return -1; + _i_INDENT(1); + p = scratch; + } + *p++ = h2c[(*buf >> 4) & 0x0F]; + *p++ = h2c[*buf & 0x0F]; + *p++ = 0x20; + } + + if(p > scratch) { + p--; /* Remove the tail space */ + if(cb(scratch, p - scratch, app_key) < 0) + return -1; + } + + return 0; +} + +int +OCTET_STRING_print_utf8(const asn_TYPE_descriptor_t *td, const void *sptr, + int ilevel, asn_app_consume_bytes_f *cb, + void *app_key) { + const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; + + (void)td; /* Unused argument */ + (void)ilevel; /* Unused argument */ + + if(st && (st->buf || !st->size)) { + return (cb(st->buf, st->size, app_key) < 0) ? -1 : 0; + } else { + return (cb("", 8, app_key) < 0) ? -1 : 0; + } +} + +void +OCTET_STRING_free(const asn_TYPE_descriptor_t *td, void *sptr, + enum asn_struct_free_method method) { + OCTET_STRING_t *st = (OCTET_STRING_t *)sptr; + const asn_OCTET_STRING_specifics_t *specs; + asn_struct_ctx_t *ctx; + struct _stack *stck; + + if(!td || !st) + return; + + specs = td->specifics + ? (const asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_SPC_OCTET_STRING_specs; + ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); + + ASN_DEBUG("Freeing %s as OCTET STRING", td->name); + + if(st->buf) { + FREEMEM(st->buf); + st->buf = 0; + } + + /* + * Remove decode-time stack. + */ + stck = (struct _stack *)ctx->ptr; + if(stck) { + while(stck->tail) { + struct _stack_el *sel = stck->tail; + stck->tail = sel->prev; + FREEMEM(sel); + } + FREEMEM(stck); + } + + switch(method) { + case ASFM_FREE_EVERYTHING: + FREEMEM(sptr); + break; + case ASFM_FREE_UNDERLYING: + break; + case ASFM_FREE_UNDERLYING_AND_RESET: + memset(sptr, 0, + td->specifics + ? ((const asn_OCTET_STRING_specifics_t *)(td->specifics)) + ->struct_size + : sizeof(OCTET_STRING_t)); + break; + } +} + +/* + * Conversion routines. + */ +int +OCTET_STRING_fromBuf(OCTET_STRING_t *st, const char *str, int len) { + void *buf; + + if(st == 0 || (str == 0 && len)) { + errno = EINVAL; + return -1; + } + + /* + * Clear the OCTET STRING. + */ + if(str == NULL) { + FREEMEM(st->buf); + st->buf = 0; + st->size = 0; + return 0; + } + + /* Determine the original string size, if not explicitly given */ + if(len < 0) + len = strlen(str); + + /* Allocate and fill the memory */ + buf = MALLOC(len + 1); + if(buf == NULL) + return -1; + + memcpy(buf, str, len); + ((uint8_t *)buf)[len] = '\0'; /* Couldn't use memcpy(len+1)! */ + FREEMEM(st->buf); + st->buf = (uint8_t *)buf; + st->size = len; + + return 0; +} + +OCTET_STRING_t * +OCTET_STRING_new_fromBuf(const asn_TYPE_descriptor_t *td, const char *str, + int len) { + const asn_OCTET_STRING_specifics_t *specs = + td->specifics ? (const asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_SPC_OCTET_STRING_specs; + OCTET_STRING_t *st; + + st = (OCTET_STRING_t *)CALLOC(1, specs->struct_size); + if(st && str && OCTET_STRING_fromBuf(st, str, len)) { + FREEMEM(st); + st = NULL; + } + + return st; +} + +/* + * Lexicographically compare the common prefix of both strings, + * and if it is the same return -1 for the smallest string. + */ +int +OCTET_STRING_compare(const asn_TYPE_descriptor_t *td, const void *aptr, + const void *bptr) { + const asn_OCTET_STRING_specifics_t *specs = td->specifics; + const OCTET_STRING_t *a = aptr; + const OCTET_STRING_t *b = bptr; + + assert(!specs || specs->subvariant != ASN_OSUBV_BIT); + + if(a && b) { + size_t common_prefix_size = a->size <= b->size ? a->size : b->size; + int ret = memcmp(a->buf, b->buf, common_prefix_size); + if(ret == 0) { + /* Figure out which string with equal prefixes is longer. */ + if(a->size < b->size) { + return -1; + } else if(a->size > b->size) { + return 1; + } else { + return 0; + } + } else { + return ret < 0 ? -1 : 1; + } + } else if(!a && !b) { + return 0; + } else if(!a) { + return -1; + } else { + return 1; + } + +} + +/* + * Biased function for randomizing character values around their limits. + */ +static uint32_t +OCTET_STRING__random_char(unsigned long lb, unsigned long ub) { + assert(lb <= ub); + switch(asn_random_between(0, 16)) { + case 0: + if(lb < ub) return lb + 1; + /* Fall through */ + case 1: + return lb; + case 2: + if(lb < ub) return ub - 1; + /* Fall through */ + case 3: + return ub; + default: + return asn_random_between(lb, ub); + } +} + + +size_t +OCTET_STRING_random_length_constrained( + const asn_TYPE_descriptor_t *td, + const asn_encoding_constraints_t *constraints, size_t max_length) { + const unsigned lengths[] = {0, 1, 2, 3, 4, 8, + 126, 127, 128, 16383, 16384, 16385, + 65534, 65535, 65536, 65537}; + size_t rnd_len; + + /* Figure out how far we should go */ + rnd_len = lengths[asn_random_between( + 0, sizeof(lengths) / sizeof(lengths[0]) - 1)]; + + if(!constraints || !constraints->per_constraints) + constraints = &td->encoding_constraints; + if(constraints->per_constraints) { + const asn_per_constraint_t *pc = &constraints->per_constraints->size; + if(pc->flags & APC_CONSTRAINED) { + long suggested_upper_bound = pc->upper_bound < (ssize_t)max_length + ? pc->upper_bound + : (ssize_t)max_length; + if(max_length <= (size_t)pc->lower_bound) { + return pc->lower_bound; + } + if(pc->flags & APC_EXTENSIBLE) { + switch(asn_random_between(0, 5)) { + case 0: + if(pc->lower_bound > 0) { + rnd_len = pc->lower_bound - 1; + break; + } + /* Fall through */ + case 1: + rnd_len = pc->upper_bound + 1; + break; + case 2: + /* Keep rnd_len from the table */ + if(rnd_len <= max_length) { + break; + } + /* Fall through */ + default: + rnd_len = asn_random_between(pc->lower_bound, + suggested_upper_bound); + } + } else { + rnd_len = + asn_random_between(pc->lower_bound, suggested_upper_bound); + } + } else { + rnd_len = asn_random_between(0, max_length); + } + } else if(rnd_len > max_length) { + rnd_len = asn_random_between(0, max_length); + } + + return rnd_len; +} + +asn_random_fill_result_t +OCTET_STRING_random_fill(const asn_TYPE_descriptor_t *td, void **sptr, + const asn_encoding_constraints_t *constraints, + size_t max_length) { + const asn_OCTET_STRING_specifics_t *specs = td->specifics + ? (const asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_SPC_OCTET_STRING_specs; + asn_random_fill_result_t result_ok = {ARFILL_OK, 1}; + asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0}; + asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0}; + unsigned int unit_bytes = 1; + unsigned long clb = 0; /* Lower bound on char */ + unsigned long cub = 255; /* Higher bound on char value */ + uint8_t *buf; + uint8_t *bend; + uint8_t *b; + size_t rnd_len; + OCTET_STRING_t *st; + + if(max_length == 0 && !*sptr) return result_skipped; + + switch(specs->subvariant) { + default: + case ASN_OSUBV_ANY: + return result_failed; + case ASN_OSUBV_BIT: + /* Handled by BIT_STRING itself. */ + return result_failed; + case ASN_OSUBV_STR: + unit_bytes = 1; + clb = 0; + cub = 255; + break; + case ASN_OSUBV_U16: + unit_bytes = 2; + clb = 0; + cub = 65535; + break; + case ASN_OSUBV_U32: + unit_bytes = 4; + clb = 0; + cub = 0x10FFFF; + break; + } + + if(!constraints || !constraints->per_constraints) + constraints = &td->encoding_constraints; + if(constraints->per_constraints) { + const asn_per_constraint_t *pc = &constraints->per_constraints->value; + if(pc->flags & APC_SEMI_CONSTRAINED) { + clb = pc->lower_bound; + } else if(pc->flags & APC_CONSTRAINED) { + clb = pc->lower_bound; + cub = pc->upper_bound; + } + } + + rnd_len = + OCTET_STRING_random_length_constrained(td, constraints, max_length); + + buf = CALLOC(unit_bytes, rnd_len + 1); + if(!buf) return result_failed; + + bend = &buf[unit_bytes * rnd_len]; + + switch(unit_bytes) { + case 1: + for(b = buf; b < bend; b += unit_bytes) { + *(uint8_t *)b = OCTET_STRING__random_char(clb, cub); + } + *(uint8_t *)b = 0; + break; + case 2: + for(b = buf; b < bend; b += unit_bytes) { + uint32_t code = OCTET_STRING__random_char(clb, cub); + b[0] = code >> 8; + b[1] = code; + } + *(uint16_t *)b = 0; + break; + case 4: + for(b = buf; b < bend; b += unit_bytes) { + uint32_t code = OCTET_STRING__random_char(clb, cub); + b[0] = code >> 24; + b[1] = code >> 16; + b[2] = code >> 8; + b[3] = code; + } + *(uint32_t *)b = 0; + break; + } + + if(*sptr) { + st = *sptr; + FREEMEM(st->buf); + } else { + st = (OCTET_STRING_t *)(*sptr = CALLOC(1, specs->struct_size)); + if(!st) { + FREEMEM(buf); + return result_failed; + } + } + + st->buf = buf; + st->size = unit_bytes * rnd_len; + + result_ok.length = st->size; + return result_ok; +} diff --git a/Vendor/asn1/include/OCTET_STRING.h b/Vendor/asn1/include/OCTET_STRING.h new file mode 100644 index 0000000..bb06dc6 --- /dev/null +++ b/Vendor/asn1/include/OCTET_STRING.h @@ -0,0 +1,100 @@ +/*- + * Copyright (c) 2003-2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _OCTET_STRING_H_ +#define _OCTET_STRING_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct OCTET_STRING { + uint8_t *buf; /* Buffer with consecutive OCTET_STRING bits */ + size_t size; /* Size of the buffer */ + + asn_struct_ctx_t _asn_ctx; /* Parsing across buffer boundaries */ +} OCTET_STRING_t; + +extern asn_TYPE_descriptor_t asn_DEF_OCTET_STRING; +extern asn_TYPE_operation_t asn_OP_OCTET_STRING; + +asn_struct_free_f OCTET_STRING_free; +asn_struct_print_f OCTET_STRING_print; +asn_struct_print_f OCTET_STRING_print_utf8; +asn_struct_compare_f OCTET_STRING_compare; +ber_type_decoder_f OCTET_STRING_decode_ber; +der_type_encoder_f OCTET_STRING_encode_der; +xer_type_decoder_f OCTET_STRING_decode_xer_hex; /* Hexadecimal */ +xer_type_decoder_f OCTET_STRING_decode_xer_binary; /* 01010111010 */ +xer_type_decoder_f OCTET_STRING_decode_xer_utf8; /* ASCII/UTF-8 */ +xer_type_encoder_f OCTET_STRING_encode_xer; +xer_type_encoder_f OCTET_STRING_encode_xer_utf8; +oer_type_decoder_f OCTET_STRING_decode_oer; +oer_type_encoder_f OCTET_STRING_encode_oer; +per_type_decoder_f OCTET_STRING_decode_uper; +per_type_encoder_f OCTET_STRING_encode_uper; +asn_random_fill_f OCTET_STRING_random_fill; + +#define OCTET_STRING_constraint asn_generic_no_constraint +#define OCTET_STRING_decode_xer OCTET_STRING_decode_xer_hex + +/****************************** + * Handy conversion routines. * + ******************************/ + +/* + * This function clears the previous value of the OCTET STRING (if any) + * and then allocates a new memory with the specified content (str/size). + * If size = -1, the size of the original string will be determined + * using strlen(str). + * If str equals to NULL, the function will silently clear the + * current contents of the OCTET STRING. + * Returns 0 if it was possible to perform operation, -1 otherwise. + */ +int OCTET_STRING_fromBuf(OCTET_STRING_t *s, const char *str, int size); + +/* Handy conversion from the C string into the OCTET STRING. */ +#define OCTET_STRING_fromString(s, str) OCTET_STRING_fromBuf(s, str, -1) + +/* + * Allocate and fill the new OCTET STRING and return a pointer to the newly + * allocated object. NULL is permitted in str: the function will just allocate + * empty OCTET STRING. + */ +OCTET_STRING_t *OCTET_STRING_new_fromBuf(const asn_TYPE_descriptor_t *td, + const char *str, int size); + +/**************************** + * Internally useful stuff. * + ****************************/ + +typedef struct asn_OCTET_STRING_specifics_s { + /* + * Target structure description. + */ + unsigned struct_size; /* Size of the structure */ + unsigned ctx_offset; /* Offset of the asn_struct_ctx_t member */ + + enum asn_OS_Subvariant { + ASN_OSUBV_ANY, /* The open type (ANY) */ + ASN_OSUBV_BIT, /* BIT STRING */ + ASN_OSUBV_STR, /* String types, not {BMP,Universal}String */ + ASN_OSUBV_U16, /* 16-bit character (BMPString) */ + ASN_OSUBV_U32 /* 32-bit character (UniversalString) */ + } subvariant; +} asn_OCTET_STRING_specifics_t; + +extern asn_OCTET_STRING_specifics_t asn_SPC_OCTET_STRING_specs; + +size_t OCTET_STRING_random_length_constrained( + const asn_TYPE_descriptor_t *, const asn_encoding_constraints_t *, + size_t max_length); + +#ifdef __cplusplus +} +#endif + +#endif /* _OCTET_STRING_H_ */ diff --git a/Vendor/asn1/include/OCTET_STRING_oer.c b/Vendor/asn1/include/OCTET_STRING_oer.c new file mode 100644 index 0000000..c16faea --- /dev/null +++ b/Vendor/asn1/include/OCTET_STRING_oer.c @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2017 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef ASN_DISABLE_OER_SUPPORT + +#include +#include +#include + +asn_dec_rval_t +OCTET_STRING_decode_oer(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, + const asn_oer_constraints_t *constraints, void **sptr, + const void *ptr, size_t size) { + const asn_OCTET_STRING_specifics_t *specs = + td->specifics ? (const asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_SPC_OCTET_STRING_specs; + OCTET_STRING_t *st = (OCTET_STRING_t *)*sptr; + const asn_oer_constraints_t *cts = + constraints ? constraints : td->encoding_constraints.oer_constraints; + ssize_t ct_size = cts ? cts->size : -1; + asn_dec_rval_t rval = {RC_OK, 0}; + size_t expected_length = 0; + + size_t unit_bytes; + switch(specs->subvariant) { + default: + case ASN_OSUBV_BIT: + ASN_DEBUG("Invalid use of OCTET STRING to decode BIT STRING"); + ASN__DECODE_FAILED; + case ASN_OSUBV_ANY: + /* Fall through */ + case ASN_OSUBV_STR: + unit_bytes = 1; + break; + case ASN_OSUBV_U16: + unit_bytes = 2; + break; + case ASN_OSUBV_U32: + unit_bytes = 4; + break; + } + + (void)opt_codec_ctx; + + if(!st) { + st = (OCTET_STRING_t *)(*sptr = CALLOC(1, specs->struct_size)); + if(!st) ASN__DECODE_FAILED; + } + + if(ct_size >= 0) { + expected_length = unit_bytes * ct_size; + } else { + /* + * X.696 (08/2015) #27.2 + * Encode length determinant as _number of octets_, but only + * if upper bound is not equal to lower bound. + */ + ssize_t len_len = oer_fetch_length(ptr, size, &expected_length); + if(len_len > 0) { + rval.consumed = len_len; + ptr = (const char *)ptr + len_len; + size -= len_len; + } else if(len_len == 0) { + ASN__DECODE_STARVED; + } else if(len_len < 0) { + ASN__DECODE_FAILED; + } + + if(expected_length % unit_bytes != 0) { + ASN_DEBUG( + "Data size %" ASN_PRI_SIZE " bytes is not consistent with multiplier %" ASN_PRI_SIZE "", + expected_length, unit_bytes); + ASN__DECODE_FAILED; + } + } + + if(size < expected_length) { + ASN__DECODE_STARVED; + } else { + uint8_t *buf = MALLOC(expected_length + 1); + if(buf == NULL) { + ASN__DECODE_FAILED; + } else { + memcpy(buf, ptr, expected_length); + buf[expected_length] = '\0'; + } + FREEMEM(st->buf); + st->buf = buf; + st->size = expected_length; + + rval.consumed += expected_length; + return rval; + } +} + +/* + * Encode as Canonical OER. + */ +asn_enc_rval_t +OCTET_STRING_encode_oer(const asn_TYPE_descriptor_t *td, + const asn_oer_constraints_t *constraints, + const void *sptr, asn_app_consume_bytes_f *cb, + void *app_key) { + const asn_OCTET_STRING_specifics_t *specs = + td->specifics ? (const asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_SPC_OCTET_STRING_specs; + const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; + const asn_oer_constraints_t *cts = + constraints ? constraints : td->encoding_constraints.oer_constraints; + ssize_t ct_size = cts ? cts->size : -1; + asn_enc_rval_t er = {0, 0, 0}; + + if(!st) ASN__ENCODE_FAILED; + + ASN_DEBUG("Encoding %s %" ASN_PRI_SIZE " as OCTET STRING", td ? td->name : "", st->size); + + if(ct_size >= 0) { + /* + * Check that available data matches the constraint + */ + size_t unit_bytes; + switch(specs->subvariant) { + default: + case ASN_OSUBV_BIT: + ASN_DEBUG("Invalid use of OCTET STRING to encode BIT STRING"); + ASN__ENCODE_FAILED; + case ASN_OSUBV_ANY: + /* Fall through */ + case ASN_OSUBV_STR: + unit_bytes = 1; + break; + case ASN_OSUBV_U16: + unit_bytes = 2; + break; + case ASN_OSUBV_U32: + unit_bytes = 4; + break; + } + + if(st->size != unit_bytes * (size_t)ct_size) { + ASN_DEBUG( + "Trying to encode %s (%" ASN_PRI_SIZE " bytes) which doesn't fit SIZE " + "constraint (%" ASN_PRI_SIZE ")", + td->name, st->size, ct_size); + ASN__ENCODE_FAILED; + } + } else { + /* + * X.696 (08/2015) #27.2 + * Encode length determinant as _number of octets_, but only + * if upper bound is not equal to lower bound. + */ + ssize_t ret = oer_serialize_length(st->size, cb, app_key); + if(ret < 0) { + ASN__ENCODE_FAILED; + } + er.encoded += ret; + } + + er.encoded += st->size; + if(cb(st->buf, st->size, app_key) < 0) { + ASN__ENCODE_FAILED; + } else { + ASN__ENCODED_OK(er); + } +} + +#endif /* ASN_DISABLE_OER_SUPPORT */ diff --git a/Vendor/asn1/include/OPEN_TYPE.c b/Vendor/asn1/include/OPEN_TYPE.c new file mode 100644 index 0000000..c672992 --- /dev/null +++ b/Vendor/asn1/include/OPEN_TYPE.c @@ -0,0 +1,402 @@ +/* + * Copyright (c) 2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include +#include +#include + +asn_TYPE_operation_t asn_OP_OPEN_TYPE = { + OPEN_TYPE_free, + OPEN_TYPE_print, + OPEN_TYPE_compare, + OPEN_TYPE_decode_ber, + OPEN_TYPE_encode_der, + OPEN_TYPE_decode_xer, + OPEN_TYPE_encode_xer, + 0, 0, /* No OER support, use "-gen-OER" to enable */ +#ifdef ASN_DISABLE_PER_SUPPORT + 0, 0, +#else + OPEN_TYPE_decode_uper, + OPEN_TYPE_encode_uper, +#endif + 0, /* Random fill is not supported for open type */ + 0, /* Use generic outmost tag fetcher */ +}; + +#undef ADVANCE +#define ADVANCE(num_bytes) \ + do { \ + size_t num = num_bytes; \ + ptr = ((const char *)ptr) + num; \ + size -= num; \ + consumed_myself += num; \ + } while(0) + +asn_dec_rval_t +OPEN_TYPE_ber_get(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, void *sptr, + const asn_TYPE_member_t *elm, const void *ptr, size_t size) { + size_t consumed_myself = 0; + asn_type_selector_result_t selected; + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + void *inner_value; + asn_dec_rval_t rv; + + if(!(elm->flags & ATF_OPEN_TYPE)) { + ASN__DECODE_FAILED; + } + + if(!elm->type_selector) { + ASN_DEBUG("Type selector is not defined for Open Type %s->%s->%s", + td->name, elm->name, elm->type->name); + ASN__DECODE_FAILED; + } + + selected = elm->type_selector(td, sptr); + if(!selected.presence_index) { + ASN__DECODE_FAILED; + } + + /* Fetch the pointer to this member */ + if(elm->flags & ATF_POINTER) { + memb_ptr2 = (void **)((char *)sptr + elm->memb_offset); + } else { + memb_ptr = (char *)sptr + elm->memb_offset; + memb_ptr2 = &memb_ptr; + } + if(*memb_ptr2 != NULL) { + /* Make sure we reset the structure first before encoding */ + if(CHOICE_variant_set_presence(elm->type, *memb_ptr2, 0) != 0) { + ASN__DECODE_FAILED; + } + } + + inner_value = + (char *)*memb_ptr2 + + elm->type->elements[selected.presence_index - 1].memb_offset; + + ASN_DEBUG("presence %d\n", selected.presence_index); + + rv = selected.type_descriptor->op->ber_decoder( + opt_codec_ctx, selected.type_descriptor, &inner_value, ptr, size, + elm->tag_mode); + ADVANCE(rv.consumed); + rv.consumed = 0; + switch(rv.code) { + case RC_OK: + if(CHOICE_variant_set_presence(elm->type, *memb_ptr2, + selected.presence_index) + == 0) { + rv.code = RC_OK; + rv.consumed = consumed_myself; + return rv; + } else { + /* Oh, now a full-blown failure failure */ + } + /* Fall through */ + case RC_FAIL: + rv.consumed = consumed_myself; + /* Fall through */ + case RC_WMORE: + break; + } + + if(*memb_ptr2) { + const asn_CHOICE_specifics_t *specs = + selected.type_descriptor->specifics; + if(elm->flags & ATF_POINTER) { + ASN_STRUCT_FREE(*selected.type_descriptor, inner_value); + *memb_ptr2 = NULL; + } else { + ASN_STRUCT_FREE_CONTENTS_ONLY(*selected.type_descriptor, + inner_value); + memset(*memb_ptr2, 0, specs->struct_size); + } + } + return rv; +} + +asn_dec_rval_t +OPEN_TYPE_xer_get(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, void *sptr, + const asn_TYPE_member_t *elm, const void *ptr, size_t size) { + size_t consumed_myself = 0; + asn_type_selector_result_t selected; + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + void *inner_value; + asn_dec_rval_t rv; + + int xer_context = 0; + ssize_t ch_size; + pxer_chunk_type_e ch_type; + + if(!(elm->flags & ATF_OPEN_TYPE)) { + ASN__DECODE_FAILED; + } + + if(!elm->type_selector) { + ASN_DEBUG("Type selector is not defined for Open Type %s->%s->%s", + td->name, elm->name, elm->type->name); + ASN__DECODE_FAILED; + } + + selected = elm->type_selector(td, sptr); + if(!selected.presence_index) { + ASN__DECODE_FAILED; + } + + /* Fetch the pointer to this member */ + assert(elm->flags == ATF_OPEN_TYPE); + if(elm->flags & ATF_POINTER) { + memb_ptr2 = (void **)((char *)sptr + elm->memb_offset); + } else { + memb_ptr = (char *)sptr + elm->memb_offset; + memb_ptr2 = &memb_ptr; + } + if(*memb_ptr2 != NULL) { + /* Make sure we reset the structure first before encoding */ + if(CHOICE_variant_set_presence(elm->type, *memb_ptr2, 0) + != 0) { + ASN__DECODE_FAILED; + } + } + + /* + * Confirm wrapper. + */ + for(;;) { + ch_size = xer_next_token(&xer_context, ptr, size, &ch_type); + if(ch_size < 0) { + ASN__DECODE_FAILED; + } else { + switch(ch_type) { + case PXER_WMORE: + ASN__DECODE_STARVED; + case PXER_COMMENT: + case PXER_TEXT: + ADVANCE(ch_size); + continue; + case PXER_TAG: + break; + } + break; + } + } + + /* + * Wrapper value confirmed. + */ + switch(xer_check_tag(ptr, ch_size, elm->name)) { + case XCT_OPENING: + ADVANCE(ch_size); + break; + case XCT_BROKEN: + default: + ASN__DECODE_FAILED; + } + + inner_value = + (char *)*memb_ptr2 + + elm->type->elements[selected.presence_index - 1].memb_offset; + + rv = selected.type_descriptor->op->xer_decoder( + opt_codec_ctx, selected.type_descriptor, &inner_value, NULL, ptr, size); + ADVANCE(rv.consumed); + rv.consumed = 0; + switch(rv.code) { + case RC_OK: + if(CHOICE_variant_set_presence(elm->type, *memb_ptr2, + selected.presence_index) + == 0) { + break; + } else { + rv.code = RC_FAIL; + } + /* Fall through */ + case RC_FAIL: + /* Point to a best position where failure occurred */ + rv.consumed = consumed_myself; + /* Fall through */ + case RC_WMORE: + /* Wrt. rv.consumed==0: + * In case a genuine RC_WMORE, the whole Open Type decoding + * will have to be restarted. + */ + if(*memb_ptr2) { + const asn_CHOICE_specifics_t *specs = + selected.type_descriptor->specifics; + if(elm->flags & ATF_POINTER) { + ASN_STRUCT_FREE(*selected.type_descriptor, inner_value); + *memb_ptr2 = NULL; + } else { + ASN_STRUCT_FREE_CONTENTS_ONLY(*selected.type_descriptor, + inner_value); + memset(*memb_ptr2, 0, specs->struct_size); + } + } + return rv; + } + + /* + * Finalize wrapper. + */ + for(;;) { + ch_size = xer_next_token(&xer_context, ptr, size, &ch_type); + if(ch_size < 0) { + ASN__DECODE_FAILED; + } else { + switch(ch_type) { + case PXER_WMORE: + ASN__DECODE_STARVED; + case PXER_COMMENT: + case PXER_TEXT: + ADVANCE(ch_size); + continue; + case PXER_TAG: + break; + } + break; + } + } + + /* + * Wrapper value confirmed. + */ + switch(xer_check_tag(ptr, ch_size, elm->name)) { + case XCT_CLOSING: + ADVANCE(ch_size); + break; + case XCT_BROKEN: + default: + ASN__DECODE_FAILED; + } + + rv.consumed += consumed_myself; + + return rv; +} + + +#ifndef ASN_DISABLE_PER_SUPPORT + +asn_dec_rval_t +OPEN_TYPE_uper_get(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, void *sptr, + const asn_TYPE_member_t *elm, asn_per_data_t *pd) { + asn_type_selector_result_t selected; + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + void *inner_value; + asn_dec_rval_t rv; + + if(!(elm->flags & ATF_OPEN_TYPE)) { + ASN__DECODE_FAILED; + } + + if(!elm->type_selector) { + ASN_DEBUG("Type selector is not defined for Open Type %s->%s->%s", + td->name, elm->name, elm->type->name); + ASN__DECODE_FAILED; + } + + selected = elm->type_selector(td, sptr); + if(!selected.presence_index) { + ASN__DECODE_FAILED; + } + + /* Fetch the pointer to this member */ + assert(elm->flags == ATF_OPEN_TYPE); + if(elm->flags & ATF_POINTER) { + memb_ptr2 = (void **)((char *)sptr + elm->memb_offset); + } else { + memb_ptr = (char *)sptr + elm->memb_offset; + memb_ptr2 = &memb_ptr; + } + if(*memb_ptr2 != NULL) { + /* Make sure we reset the structure first before encoding */ + if(CHOICE_variant_set_presence(elm->type, *memb_ptr2, 0) + != 0) { + ASN__DECODE_FAILED; + } + } + + inner_value = + (char *)*memb_ptr2 + + elm->type->elements[selected.presence_index - 1].memb_offset; + + rv = uper_open_type_get(opt_codec_ctx, selected.type_descriptor, NULL, + &inner_value, pd); + switch(rv.code) { + case RC_OK: + if(CHOICE_variant_set_presence(elm->type, *memb_ptr2, + selected.presence_index) + == 0) { + break; + } else { + rv.code = RC_FAIL; + } + /* Fall through */ + case RC_WMORE: + case RC_FAIL: + if(*memb_ptr2) { + const asn_CHOICE_specifics_t *specs = + selected.type_descriptor->specifics; + if(elm->flags & ATF_POINTER) { + ASN_STRUCT_FREE(*selected.type_descriptor, inner_value); + *memb_ptr2 = NULL; + } else { + ASN_STRUCT_FREE_CONTENTS_ONLY(*selected.type_descriptor, + inner_value); + memset(*memb_ptr2, 0, specs->struct_size); + } + } + } + return rv; +} + +asn_enc_rval_t +OPEN_TYPE_encode_uper(const asn_TYPE_descriptor_t *td, + const asn_per_constraints_t *constraints, + const void *sptr, asn_per_outp_t *po) { + const void *memb_ptr; /* Pointer to the member */ + asn_TYPE_member_t *elm; /* CHOICE's element */ + asn_enc_rval_t er; + unsigned present; + + (void)constraints; + + present = CHOICE_variant_get_presence(td, sptr); + if(present == 0 || present > td->elements_count) { + ASN__ENCODE_FAILED; + } else { + present--; + } + + ASN_DEBUG("Encoding %s OPEN TYPE element %d", td->name, present); + + elm = &td->elements[present]; + if(elm->flags & ATF_POINTER) { + /* Member is a pointer to another structure */ + memb_ptr = + *(const void *const *)((const char *)sptr + elm->memb_offset); + if(!memb_ptr) ASN__ENCODE_FAILED; + } else { + memb_ptr = (const char *)sptr + elm->memb_offset; + } + + if(uper_open_type_put(elm->type, NULL, memb_ptr, po) < 0) { + ASN__ENCODE_FAILED; + } + + er.encoded = 0; + ASN__ENCODED_OK(er); +} + + +#endif /* ASN_DISABLE_PER_SUPPORT */ diff --git a/Vendor/asn1/include/OPEN_TYPE.h b/Vendor/asn1/include/OPEN_TYPE.h new file mode 100644 index 0000000..d0f02fd --- /dev/null +++ b/Vendor/asn1/include/OPEN_TYPE.h @@ -0,0 +1,63 @@ +/*- + * Copyright (c) 2017-2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef ASN_OPEN_TYPE_H +#define ASN_OPEN_TYPE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define OPEN_TYPE_free CHOICE_free +#define OPEN_TYPE_print CHOICE_print +#define OPEN_TYPE_compare CHOICE_compare +#define OPEN_TYPE_constraint CHOICE_constraint +#define OPEN_TYPE_decode_ber NULL +#define OPEN_TYPE_encode_der CHOICE_encode_der +#define OPEN_TYPE_decode_xer NULL +#define OPEN_TYPE_encode_xer CHOICE_encode_xer +#define OPEN_TYPE_decode_uper NULL + +extern asn_TYPE_operation_t asn_OP_OPEN_TYPE; + +/* + * Decode an Open Type which is potentially constraiend + * by the other members of the parent structure. + */ +asn_dec_rval_t OPEN_TYPE_ber_get(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *parent_type, + void *parent_structure, + const asn_TYPE_member_t *element, + const void *ptr, size_t size); + +asn_dec_rval_t OPEN_TYPE_xer_get(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *parent_type, + void *parent_structure, + const asn_TYPE_member_t *element, + const void *ptr, size_t size); + +asn_dec_rval_t OPEN_TYPE_oer_get(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *parent_type, + void *parent_structure, + asn_TYPE_member_t *element, const void *ptr, + size_t size); + +asn_dec_rval_t OPEN_TYPE_uper_get(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *parent_type, + void *parent_structure, + const asn_TYPE_member_t *element, + asn_per_data_t *pd); + +asn_enc_rval_t OPEN_TYPE_encode_uper( + const asn_TYPE_descriptor_t *type_descriptor, + const asn_per_constraints_t *constraints, const void *struct_ptr, + asn_per_outp_t *per_output); + +#ifdef __cplusplus +} +#endif + +#endif /* ASN_OPEN_TYPE_H */ diff --git a/Vendor/asn1/include/OPEN_TYPE_oer.c b/Vendor/asn1/include/OPEN_TYPE_oer.c new file mode 100644 index 0000000..dd2f5c6 --- /dev/null +++ b/Vendor/asn1/include/OPEN_TYPE_oer.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include +#include + +asn_dec_rval_t +OPEN_TYPE_oer_get(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, void *sptr, + asn_TYPE_member_t *elm, const void *ptr, size_t size) { + asn_type_selector_result_t selected; + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + void *inner_value; + asn_dec_rval_t rv; + size_t ot_ret; + + + if(!(elm->flags & ATF_OPEN_TYPE)) { + ASN__DECODE_FAILED; + } + + if(!elm->type_selector) { + ASN_DEBUG("Type selector is not defined for Open Type %s->%s->%s", + td->name, elm->name, elm->type->name); + ASN__DECODE_FAILED; + } + + selected = elm->type_selector(td, sptr); + if(!selected.presence_index) { + ASN__DECODE_FAILED; + } + + /* Fetch the pointer to this member */ + if(elm->flags & ATF_POINTER) { + memb_ptr2 = (void **)((char *)sptr + elm->memb_offset); + } else { + memb_ptr = (char *)sptr + elm->memb_offset; + memb_ptr2 = &memb_ptr; + } + if(*memb_ptr2 != NULL) { + /* Make sure we reset the structure first before encoding */ + if(CHOICE_variant_set_presence(elm->type, *memb_ptr2, 0) != 0) { + ASN__DECODE_FAILED; + } + } + + inner_value = + (char *)*memb_ptr2 + + elm->type->elements[selected.presence_index - 1].memb_offset; + + ot_ret = oer_open_type_get(opt_codec_ctx, selected.type_descriptor, NULL, + &inner_value, ptr, size); + switch(ot_ret) { + default: + if(CHOICE_variant_set_presence(elm->type, *memb_ptr2, + selected.presence_index) + == 0) { + rv.code = RC_OK; + rv.consumed = ot_ret; + return rv; + } else { + /* Oh, now a full-blown failure failure */ + } + /* Fall through */ + case -1: + rv.code = RC_FAIL; + rv.consumed = ot_ret; + break; + case 0: + rv.code = RC_WMORE; + rv.consumed = 0; + break; + } + + if(*memb_ptr2) { + const asn_CHOICE_specifics_t *specs = + selected.type_descriptor->specifics; + if(elm->flags & ATF_POINTER) { + ASN_STRUCT_FREE(*selected.type_descriptor, inner_value); + *memb_ptr2 = NULL; + } else { + ASN_STRUCT_FREE_CONTENTS_ONLY(*selected.type_descriptor, + inner_value); + memset(*memb_ptr2, 0, specs->struct_size); + } + } + return rv; +} diff --git a/Vendor/asn1/include/Payload.c b/Vendor/asn1/include/Payload.c new file mode 100644 index 0000000..934b1bc --- /dev/null +++ b/Vendor/asn1/include/Payload.c @@ -0,0 +1,44 @@ +/* + * Generated by asn1c-0.9.29 (http://lionet.info/asn1c) + * From ASN.1 module "ReceiptModule" + * found in "ASN1PayloadStructure" + * `asn1c -fnative-types` + */ + +#include "Payload.h" + +static asn_TYPE_member_t asn_MBR_Payload_1[] = { + { ATF_POINTER, 0, 0, + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)), + 0, + &asn_DEF_ReceiptAttribute, + 0, + { 0, 0, 0 }, + 0, 0, /* No default value */ + "" + }, +}; +static const ber_tlv_tag_t asn_DEF_Payload_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (17 << 2)) +}; +static asn_SET_OF_specifics_t asn_SPC_Payload_specs_1 = { + sizeof(struct Payload), + offsetof(struct Payload, _asn_ctx), + 0, /* XER encoding is XMLDelimitedItemList */ +}; +asn_TYPE_descriptor_t asn_DEF_Payload = { + "Payload", + "Payload", + &asn_OP_SET_OF, + asn_DEF_Payload_tags_1, + sizeof(asn_DEF_Payload_tags_1) + /sizeof(asn_DEF_Payload_tags_1[0]), /* 1 */ + asn_DEF_Payload_tags_1, /* Same as above */ + sizeof(asn_DEF_Payload_tags_1) + /sizeof(asn_DEF_Payload_tags_1[0]), /* 1 */ + { 0, 0, SET_OF_constraint }, + asn_MBR_Payload_1, + 1, /* Single element */ + &asn_SPC_Payload_specs_1 /* Additional specs */ +}; + diff --git a/Vendor/asn1/include/Payload.h b/Vendor/asn1/include/Payload.h new file mode 100644 index 0000000..aa51475 --- /dev/null +++ b/Vendor/asn1/include/Payload.h @@ -0,0 +1,44 @@ +/* + * Generated by asn1c-0.9.29 (http://lionet.info/asn1c) + * From ASN.1 module "ReceiptModule" + * found in "ASN1PayloadStructure" + * `asn1c -fnative-types` + */ + +#ifndef _Payload_H_ +#define _Payload_H_ + + +#include + +/* Including external dependencies */ +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Forward declarations */ +struct ReceiptAttribute; + +/* Payload */ +typedef struct Payload { + A_SET_OF(struct ReceiptAttribute) list; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} Payload_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_Payload; + +#ifdef __cplusplus +} +#endif + +/* Referred external types */ +#include "ReceiptAttribute.h" + +#endif /* _Payload_H_ */ +#include diff --git a/Vendor/asn1/include/ReceiptAttribute.c b/Vendor/asn1/include/ReceiptAttribute.c new file mode 100644 index 0000000..249bae1 --- /dev/null +++ b/Vendor/asn1/include/ReceiptAttribute.c @@ -0,0 +1,70 @@ +/* + * Generated by asn1c-0.9.29 (http://lionet.info/asn1c) + * From ASN.1 module "ReceiptModule" + * found in "ASN1PayloadStructure" + * `asn1c -fnative-types` + */ + +#include "ReceiptAttribute.h" + +asn_TYPE_member_t asn_MBR_ReceiptAttribute_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct ReceiptAttribute, type), + (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)), + 0, + &asn_DEF_NativeInteger, + 0, + { 0, 0, 0 }, + 0, 0, /* No default value */ + "type" + }, + { ATF_NOFLAGS, 0, offsetof(struct ReceiptAttribute, version), + (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)), + 0, + &asn_DEF_NativeInteger, + 0, + { 0, 0, 0 }, + 0, 0, /* No default value */ + "version" + }, + { ATF_NOFLAGS, 0, offsetof(struct ReceiptAttribute, value), + (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)), + 0, + &asn_DEF_OCTET_STRING, + 0, + { 0, 0, 0 }, + 0, 0, /* No default value */ + "value" + }, +}; +static const ber_tlv_tag_t asn_DEF_ReceiptAttribute_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static const asn_TYPE_tag2member_t asn_MAP_ReceiptAttribute_tag2el_1[] = { + { (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)), 0, 0, 1 }, /* type */ + { (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)), 1, -1, 0 }, /* version */ + { (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)), 2, 0, 0 } /* value */ +}; +asn_SEQUENCE_specifics_t asn_SPC_ReceiptAttribute_specs_1 = { + sizeof(struct ReceiptAttribute), + offsetof(struct ReceiptAttribute, _asn_ctx), + asn_MAP_ReceiptAttribute_tag2el_1, + 3, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* First extension addition */ +}; +asn_TYPE_descriptor_t asn_DEF_ReceiptAttribute = { + "ReceiptAttribute", + "ReceiptAttribute", + &asn_OP_SEQUENCE, + asn_DEF_ReceiptAttribute_tags_1, + sizeof(asn_DEF_ReceiptAttribute_tags_1) + /sizeof(asn_DEF_ReceiptAttribute_tags_1[0]), /* 1 */ + asn_DEF_ReceiptAttribute_tags_1, /* Same as above */ + sizeof(asn_DEF_ReceiptAttribute_tags_1) + /sizeof(asn_DEF_ReceiptAttribute_tags_1[0]), /* 1 */ + { 0, 0, SEQUENCE_constraint }, + asn_MBR_ReceiptAttribute_1, + 3, /* Elements count */ + &asn_SPC_ReceiptAttribute_specs_1 /* Additional specs */ +}; + diff --git a/Vendor/asn1/include/ReceiptAttribute.h b/Vendor/asn1/include/ReceiptAttribute.h new file mode 100644 index 0000000..67bee3c --- /dev/null +++ b/Vendor/asn1/include/ReceiptAttribute.h @@ -0,0 +1,43 @@ +/* + * Generated by asn1c-0.9.29 (http://lionet.info/asn1c) + * From ASN.1 module "ReceiptModule" + * found in "ASN1PayloadStructure" + * `asn1c -fnative-types` + */ + +#ifndef _ReceiptAttribute_H_ +#define _ReceiptAttribute_H_ + + +#include + +/* Including external dependencies */ +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ReceiptAttribute */ +typedef struct ReceiptAttribute { + long type; + long version; + OCTET_STRING_t value; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} ReceiptAttribute_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_ReceiptAttribute; +extern asn_SEQUENCE_specifics_t asn_SPC_ReceiptAttribute_specs_1; +extern asn_TYPE_member_t asn_MBR_ReceiptAttribute_1[3]; + +#ifdef __cplusplus +} +#endif + +#endif /* _ReceiptAttribute_H_ */ +#include diff --git a/Vendor/asn1/include/asn_SET_OF.c b/Vendor/asn1/include/asn_SET_OF.c new file mode 100644 index 0000000..944f2cb --- /dev/null +++ b/Vendor/asn1/include/asn_SET_OF.c @@ -0,0 +1,88 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include + +/* + * Add another element into the set. + */ +int +asn_set_add(void *asn_set_of_x, void *ptr) { + asn_anonymous_set_ *as = _A_SET_FROM_VOID(asn_set_of_x); + + if(as == 0 || ptr == 0) { + errno = EINVAL; /* Invalid arguments */ + return -1; + } + + /* + * Make sure there's enough space to insert an element. + */ + if(as->count == as->size) { + int _newsize = as->size ? (as->size << 1) : 4; + void *_new_arr; + _new_arr = REALLOC(as->array, _newsize * sizeof(as->array[0])); + if(_new_arr) { + as->array = (void **)_new_arr; + as->size = _newsize; + } else { + /* ENOMEM */ + return -1; + } + } + + as->array[as->count++] = ptr; + + return 0; +} + +void +asn_set_del(void *asn_set_of_x, int number, int _do_free) { + asn_anonymous_set_ *as = _A_SET_FROM_VOID(asn_set_of_x); + + if(as) { + void *ptr; + if(number < 0 || number >= as->count) + return; + + if(_do_free && as->free) { + ptr = as->array[number]; + } else { + ptr = 0; + } + + as->array[number] = as->array[--as->count]; + + /* + * Invoke the third-party function only when the state + * of the parent structure is consistent. + */ + if(ptr) as->free(ptr); + } +} + +/* + * Free the contents of the set, do not free the set itself. + */ +void +asn_set_empty(void *asn_set_of_x) { + asn_anonymous_set_ *as = _A_SET_FROM_VOID(asn_set_of_x); + + if(as) { + if(as->array) { + if(as->free) { + while(as->count--) + as->free(as->array[as->count]); + } + FREEMEM(as->array); + as->array = 0; + } + as->count = 0; + as->size = 0; + } + +} + diff --git a/Vendor/asn1/include/asn_SET_OF.h b/Vendor/asn1/include/asn_SET_OF.h new file mode 100644 index 0000000..882e1a4 --- /dev/null +++ b/Vendor/asn1/include/asn_SET_OF.h @@ -0,0 +1,72 @@ +/*- + * Copyright (c) 2003-2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef ASN_SET_OF_H +#define ASN_SET_OF_H + +#ifdef __cplusplus +#define A_SET_OF(type) \ + struct { \ + type **array; \ + int count; /* Meaningful size */ \ + int size; /* Allocated size */ \ + void (*free)(decltype(*array)); \ + } +#else /* C */ +#define A_SET_OF(type) \ + struct { \ + type **array; \ + int count; /* Meaningful size */ \ + int size; /* Allocated size */ \ + void (*free)(type *); \ + } +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define ASN_SET_ADD(headptr, ptr) \ + asn_set_add((headptr), (ptr)) + +/******************************************* + * Implementation of the SET OF structure. + */ + +/* + * Add another structure into the set by its pointer. + * RETURN VALUES: + * 0 for success and -1/errno for failure. + */ +int asn_set_add(void *asn_set_of_x, void *ptr); + +/* + * Delete the element from the set by its number (base 0). + * This is a constant-time operation. The order of elements before the + * deleted ones is guaranteed, the order of elements after the deleted + * one is NOT guaranteed. + * If _do_free is given AND the (*free) is initialized, the element + * will be freed using the custom (*free) function as well. + */ +void asn_set_del(void *asn_set_of_x, int number, int _do_free); + +/* + * Empty the contents of the set. Will free the elements, if (*free) is given. + * Will NOT free the set itself. + */ +void asn_set_empty(void *asn_set_of_x); + +/* + * Cope with different conversions requirements to/from void in C and C++. + * This is mostly useful for support library. + */ +typedef A_SET_OF(void) asn_anonymous_set_; +#define _A_SET_FROM_VOID(ptr) ((asn_anonymous_set_ *)(ptr)) +#define _A_CSET_FROM_VOID(ptr) ((const asn_anonymous_set_ *)(ptr)) + +#ifdef __cplusplus +} +#endif + +#endif /* ASN_SET_OF_H */ diff --git a/Vendor/asn1/include/asn_application.c b/Vendor/asn1/include/asn_application.c new file mode 100644 index 0000000..8ce0261 --- /dev/null +++ b/Vendor/asn1/include/asn_application.c @@ -0,0 +1,440 @@ +/* + * Copyright (c) 2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include + +static asn_enc_rval_t asn_encode_internal(const asn_codec_ctx_t *opt_codec_ctx, + enum asn_transfer_syntax syntax, + const asn_TYPE_descriptor_t *td, + const void *sptr, + asn_app_consume_bytes_f *callback, + void *callback_key); + + +struct callback_count_bytes_key { + asn_app_consume_bytes_f *callback; + void *callback_key; + size_t computed_size; +}; + +/* + * Encoder which just counts bytes that come through it. + */ +static int +callback_count_bytes_cb(const void *data, size_t size, void *keyp) { + struct callback_count_bytes_key *key = keyp; + int ret; + + ret = key->callback(data, size, key->callback_key); + if(ret >= 0) { + key->computed_size += size; + } + + return ret; +} + +struct overrun_encoder_key { + void *buffer; + size_t buffer_size; + size_t computed_size; +}; + +struct dynamic_encoder_key { + void *buffer; + size_t buffer_size; + size_t computed_size; +}; + +struct callback_failure_catch_key { + asn_app_consume_bytes_f *callback; + void *callback_key; + int callback_failed; +}; + +/* + * Encoder which doesn't stop counting bytes + * even if it reaches the end of the buffer. + */ +static int +overrun_encoder_cb(const void *data, size_t size, void *keyp) { + struct overrun_encoder_key *key = keyp; + + if(key->computed_size + size > key->buffer_size) { + /* + * Avoid accident on the next call: + * stop adding bytes to the buffer. + */ + key->buffer_size = 0; + } else { + memcpy((char *)key->buffer + key->computed_size, data, size); + } + key->computed_size += size; + + return 0; +} + +/* + * Encoder which dynamically allocates output, and continues + * to count even if allocation failed. + */ +static int +dynamic_encoder_cb(const void *data, size_t size, void *keyp) { + struct dynamic_encoder_key *key = keyp; + + if(key->buffer) { + if(key->computed_size + size >= key->buffer_size) { + void *p; + size_t new_size = key->buffer_size; + + do { + new_size *= 2; + } while(new_size <= key->computed_size + size); + + p = REALLOC(key->buffer, new_size); + if(p) { + key->buffer = p; + key->buffer_size = new_size; + } else { + FREEMEM(key->buffer); + key->buffer = 0; + key->buffer_size = 0; + key->computed_size += size; + return 0; + } + } + memcpy((char *)key->buffer + key->computed_size, data, size); + } + + key->computed_size += size; + + return 0; +} + +/* + * Encoder which help convert the application level encoder failure into EIO. + */ +static int +callback_failure_catch_cb(const void *data, size_t size, void *keyp) { + struct callback_failure_catch_key *key = keyp; + int ret; + + ret = key->callback(data, size, key->callback_key); + if(ret < 0) { + key->callback_failed = 1; + } + + return ret; +} + +asn_enc_rval_t +asn_encode(const asn_codec_ctx_t *opt_codec_ctx, + enum asn_transfer_syntax syntax, const asn_TYPE_descriptor_t *td, + const void *sptr, asn_app_consume_bytes_f *callback, void *callback_key) { + struct callback_failure_catch_key cb_key; + asn_enc_rval_t er; + + if(!callback) { + errno = EINVAL; + ASN__ENCODE_FAILED; + } + + cb_key.callback = callback; + cb_key.callback_key = callback_key; + cb_key.callback_failed = 0; + + er = asn_encode_internal(opt_codec_ctx, syntax, td, sptr, + callback_failure_catch_cb, &cb_key); + if(cb_key.callback_failed) { + assert(er.encoded == -1); + assert(errno == EBADF); + errno = EIO; + } + + return er; +} + +asn_enc_rval_t +asn_encode_to_buffer(const asn_codec_ctx_t *opt_codec_ctx, + enum asn_transfer_syntax syntax, + const asn_TYPE_descriptor_t *td, const void *sptr, + void *buffer, size_t buffer_size) { + struct overrun_encoder_key buf_key; + asn_enc_rval_t er; + + if(buffer_size > 0 && !buffer) { + errno = EINVAL; + ASN__ENCODE_FAILED; + } + + buf_key.buffer = buffer; + buf_key.buffer_size = buffer_size; + buf_key.computed_size = 0; + + er = asn_encode_internal(opt_codec_ctx, syntax, td, sptr, + overrun_encoder_cb, &buf_key); + + if(er.encoded >= 0 && (size_t)er.encoded != buf_key.computed_size) { + ASN_DEBUG("asn_encode() returned %" ASN_PRI_SSIZE + " yet produced %" ASN_PRI_SIZE " bytes", + er.encoded, buf_key.computed_size); + assert(er.encoded < 0 || (size_t)er.encoded == buf_key.computed_size); + } + + return er; +} + +asn_encode_to_new_buffer_result_t +asn_encode_to_new_buffer(const asn_codec_ctx_t *opt_codec_ctx, + enum asn_transfer_syntax syntax, + const asn_TYPE_descriptor_t *td, const void *sptr) { + struct dynamic_encoder_key buf_key; + asn_encode_to_new_buffer_result_t res; + + buf_key.buffer_size = 16; + buf_key.buffer = MALLOC(buf_key.buffer_size); + buf_key.computed_size = 0; + + res.result = asn_encode_internal(opt_codec_ctx, syntax, td, sptr, + dynamic_encoder_cb, &buf_key); + + if(res.result.encoded >= 0 + && (size_t)res.result.encoded != buf_key.computed_size) { + ASN_DEBUG("asn_encode() returned %" ASN_PRI_SSIZE + " yet produced %" ASN_PRI_SIZE " bytes", + res.result.encoded, buf_key.computed_size); + assert(res.result.encoded < 0 + || (size_t)res.result.encoded == buf_key.computed_size); + } + + res.buffer = buf_key.buffer; + + /* 0-terminate just in case. */ + if(res.buffer) { + assert(buf_key.computed_size < buf_key.buffer_size); + ((char *)res.buffer)[buf_key.computed_size] = '\0'; + } + + return res; +} + +static asn_enc_rval_t +asn_encode_internal(const asn_codec_ctx_t *opt_codec_ctx, + enum asn_transfer_syntax syntax, + const asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_consume_bytes_f *callback, void *callback_key) { + asn_enc_rval_t er; + enum xer_encoder_flags_e xer_flags = XER_F_CANONICAL; + + (void)opt_codec_ctx; /* Parameters are not checked on encode yet. */ + + if(!td || !sptr) { + errno = EINVAL; + ASN__ENCODE_FAILED; + } + + switch(syntax) { + case ATS_NONSTANDARD_PLAINTEXT: + if(td->op->print_struct) { + struct callback_count_bytes_key cb_key; + cb_key.callback = callback; + cb_key.callback_key = callback_key; + cb_key.computed_size = 0; + if(td->op->print_struct(td, sptr, 1, callback_count_bytes_cb, + &cb_key) + < 0 + || callback_count_bytes_cb("\n", 1, &cb_key) < 0) { + errno = EBADF; /* Structure has incorrect form. */ + er.encoded = -1; + er.failed_type = td; + er.structure_ptr = sptr; + } else { + er.encoded = cb_key.computed_size; + er.failed_type = 0; + er.structure_ptr = 0; + } + } else { + errno = ENOENT; /* Transfer syntax is not defined for this type. */ + ASN__ENCODE_FAILED; + } + break; + + case ATS_RANDOM: + errno = ENOENT; /* Randomization doesn't make sense on output. */ + ASN__ENCODE_FAILED; + + case ATS_BER: + /* BER is a superset of DER. */ + /* Fall through. */ + case ATS_DER: + if(td->op->der_encoder) { + er = der_encode(td, sptr, callback, callback_key); + if(er.encoded == -1) { + if(er.failed_type && er.failed_type->op->der_encoder) { + errno = EBADF; /* Structure has incorrect form. */ + } else { + errno = ENOENT; /* DER is not defined for this type. */ + } + } + } else { + errno = ENOENT; /* Transfer syntax is not defined for this type. */ + ASN__ENCODE_FAILED; + } + break; + case ATS_CER: + errno = ENOENT; /* Transfer syntax is not defined for any type. */ + ASN__ENCODE_FAILED; + +#ifdef ASN_DISABLE_OER_SUPPORT + case ATS_BASIC_OER: + case ATS_CANONICAL_OER: + errno = ENOENT; /* PER is not defined. */ + ASN__ENCODE_FAILED; + break; +#else /* ASN_DISABLE_OER_SUPPORT */ + case ATS_BASIC_OER: + /* CANONICAL-OER is a superset of BASIC-OER. */ + /* Fall through. */ + case ATS_CANONICAL_OER: + if(td->op->oer_encoder) { + er = oer_encode(td, sptr, callback, callback_key); + if(er.encoded == -1) { + if(er.failed_type && er.failed_type->op->oer_encoder) { + errno = EBADF; /* Structure has incorrect form. */ + } else { + errno = ENOENT; /* OER is not defined for this type. */ + } + } + } else { + errno = ENOENT; /* Transfer syntax is not defined for this type. */ + ASN__ENCODE_FAILED; + } + break; +#endif /* ASN_DISABLE_OER_SUPPORT */ + +#ifdef ASN_DISABLE_PER_SUPPORT + case ATS_UNALIGNED_BASIC_PER: + case ATS_UNALIGNED_CANONICAL_PER: + errno = ENOENT; /* PER is not defined. */ + ASN__ENCODE_FAILED; + break; +#else /* ASN_DISABLE_PER_SUPPORT */ + case ATS_UNALIGNED_BASIC_PER: + /* CANONICAL-UPER is a superset of BASIC-UPER. */ + /* Fall through. */ + case ATS_UNALIGNED_CANONICAL_PER: + if(td->op->uper_encoder) { + er = uper_encode(td, 0, sptr, callback, callback_key); + if(er.encoded == -1) { + if(er.failed_type && er.failed_type->op->uper_encoder) { + errno = EBADF; /* Structure has incorrect form. */ + } else { + errno = ENOENT; /* UPER is not defined for this type. */ + } + } else { + ASN_DEBUG("Complete encoded in %ld bits", (long)er.encoded); + if(er.encoded == 0) { + /* Enforce "Complete Encoding" of X.691 #11.1 */ + if(callback("\0", 1, callback_key) < 0) { + errno = EBADF; + ASN__ENCODE_FAILED; + } + er.encoded = 8; /* Exactly 8 zero bits is added. */ + } + /* Convert bits into bytes */ + er.encoded = (er.encoded + 7) >> 3; + } + } else { + errno = ENOENT; /* Transfer syntax is not defined for this type. */ + ASN__ENCODE_FAILED; + } + break; +#endif /* ASN_DISABLE_PER_SUPPORT */ + + case ATS_BASIC_XER: + /* CANONICAL-XER is a superset of BASIC-XER. */ + xer_flags &= ~XER_F_CANONICAL; + xer_flags |= XER_F_BASIC; + /* Fall through. */ + case ATS_CANONICAL_XER: + if(td->op->xer_encoder) { + er = xer_encode(td, sptr, xer_flags, callback, callback_key); + if(er.encoded == -1) { + if(er.failed_type && er.failed_type->op->xer_encoder) { + errno = EBADF; /* Structure has incorrect form. */ + } else { + errno = ENOENT; /* XER is not defined for this type. */ + } + } + } else { + errno = ENOENT; /* Transfer syntax is not defined for this type. */ + ASN__ENCODE_FAILED; + } + break; + + default: + errno = ENOENT; + ASN__ENCODE_FAILED; + } + + return er; +} + +asn_dec_rval_t +asn_decode(const asn_codec_ctx_t *opt_codec_ctx, + enum asn_transfer_syntax syntax, const asn_TYPE_descriptor_t *td, + void **sptr, const void *buffer, size_t size) { + if(!td || !td->op || !sptr || (size && !buffer)) { + ASN__DECODE_FAILED; + } + + switch(syntax) { + case ATS_CER: + case ATS_NONSTANDARD_PLAINTEXT: + default: + errno = ENOENT; + ASN__DECODE_FAILED; + + case ATS_RANDOM: + if(!td->op->random_fill) { + ASN__DECODE_FAILED; + } else { + if(asn_random_fill(td, sptr, 16000) == 0) { + asn_dec_rval_t ret = {RC_OK, 0}; + return ret; + } else { + ASN__DECODE_FAILED; + } + } + break; + + case ATS_DER: + case ATS_BER: + return ber_decode(opt_codec_ctx, td, sptr, buffer, size); + + case ATS_BASIC_OER: + case ATS_CANONICAL_OER: +#ifdef ASN_DISABLE_OER_SUPPORT + errno = ENOENT; + ASN__DECODE_FAILED; +#else + return oer_decode(opt_codec_ctx, td, sptr, buffer, size); +#endif + + case ATS_UNALIGNED_BASIC_PER: + case ATS_UNALIGNED_CANONICAL_PER: +#ifdef ASN_DISABLE_PER_SUPPORT + errno = ENOENT; + ASN__DECODE_FAILED; +#else + return uper_decode_complete(opt_codec_ctx, td, sptr, buffer, size); +#endif + + case ATS_BASIC_XER: + case ATS_CANONICAL_XER: + return xer_decode(opt_codec_ctx, td, sptr, buffer, size); + } +} + diff --git a/Vendor/asn1/include/asn_application.h b/Vendor/asn1/include/asn_application.h new file mode 100644 index 0000000..3ca9f13 --- /dev/null +++ b/Vendor/asn1/include/asn_application.h @@ -0,0 +1,169 @@ +/*- + * Copyright (c) 2004-2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +/* + * Application-level ASN.1 callbacks. + */ +#ifndef ASN_APPLICATION_H +#define ASN_APPLICATION_H + +#include "asn_system.h" /* for platform-dependent types */ +#include "asn_codecs.h" /* for ASN.1 codecs specifics */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * A selection of ASN.1 Transfer Syntaxes to use with generalized + * encoders and decoders declared further in this .h file. + */ +enum asn_transfer_syntax { + /* Avoid appearance of a default transfer syntax. */ + ATS_INVALID = 0, + /* Plaintext output (not conforming to any standard), for debugging. */ + ATS_NONSTANDARD_PLAINTEXT, + /* Returns a randomly generatede structure. */ + ATS_RANDOM, + /* + * X.690: + * BER: Basic Encoding Rules. + * DER: Distinguished Encoding Rules. + * CER: Canonical Encoding Rules. + * DER and CER are more strict variants of BER. + */ + ATS_BER, + ATS_DER, + ATS_CER, /* Only decoding is supported */ + /* + * X.696: + * OER: Octet Encoding Rules. + * CANONICAL-OER is a more strict variant of BASIC-OER. + */ + ATS_BASIC_OER, + ATS_CANONICAL_OER, + /* + * X.691: + * PER: Packed Encoding Rules. + * CANONICAL-PER is a more strict variant of BASIC-PER. + * NOTE: Produces or consumes a complete encoding (X.691 (08/2015) #11.1). + */ + ATS_UNALIGNED_BASIC_PER, + ATS_UNALIGNED_CANONICAL_PER, + /* + * X.693: + * XER: XML Encoding Rules. + * CANONICAL-XER is a more strict variant of BASIC-XER. + */ + ATS_BASIC_XER, + ATS_CANONICAL_XER +}; + +/* + * A generic encoder for any supported transfer syntax. + * RETURN VALUES: + * The (.encoded) field of the return value is REDEFINED to mean the following: + * >=0: The computed size of the encoded data. Can exceed the (buffer_size). + * -1: Error encoding the structure. See the error code in (errno): + * EINVAL: Incorrect parameters to the function, such as NULLs. + * ENOENT: Encoding transfer syntax is not defined (for this type). + * EBADF: The structure has invalid form or content constraint failed. + * The (.failed_type) and (.structure_ptr) MIGHT be set to the appropriate + * values at the place of failure, if at all possible. + * WARNING: The (.encoded) field of the return value can exceed the buffer_size. + * This is similar to snprintf(3) contract which might return values + * greater than the buffer size. + */ +asn_enc_rval_t asn_encode_to_buffer( + const asn_codec_ctx_t *opt_codec_parameters, /* See asn_codecs.h */ + enum asn_transfer_syntax, + const struct asn_TYPE_descriptor_s *type_to_encode, + const void *structure_to_encode, void *buffer, size_t buffer_size); + +/* + * A variant of asn_encode_to_buffer() with automatically allocated buffer. + * RETURN VALUES: + * On success, returns a newly allocated (.buffer) containing the whole message. + * The message size is returned in (.result.encoded). + * On failure: + * (.buffer) is NULL, + * (.result.encoded) as in asn_encode_to_buffer(), + * The errno codes as in asn_encode_to_buffer(), plus the following: + * ENOMEM: Memory allocation failed due to system or internal limits. + * The user is responsible for freeing the (.buffer). + */ +typedef struct asn_encode_to_new_buffer_result_s { + void *buffer; /* NULL if failed to encode. */ + asn_enc_rval_t result; +} asn_encode_to_new_buffer_result_t; +asn_encode_to_new_buffer_result_t asn_encode_to_new_buffer( + const asn_codec_ctx_t *opt_codec_parameters, /* See asn_codecs.h */ + enum asn_transfer_syntax, + const struct asn_TYPE_descriptor_s *type_to_encode, + const void *structure_to_encode); + + +/* + * Generic type of an application-defined callback to return various + * types of data to the application. + * EXPECTED RETURN VALUES: + * -1: Failed to consume bytes. Abort the mission. + * Non-negative return values indicate success, and ignored. + */ +typedef int(asn_app_consume_bytes_f)(const void *buffer, size_t size, + void *application_specific_key); + + +/* + * A generic encoder for any supported transfer syntax. + * Returns the comprehensive encoding result descriptor (see asn_codecs.h). + * RETURN VALUES: + * The negative (.encoded) field of the return values is accompanied with the + * following error codes (errno): + * EINVAL: Incorrect parameters to the function, such as NULLs. + * ENOENT: Encoding transfer syntax is not defined (for this type). + * EBADF: The structure has invalid form or content constraint failed. + * EIO: The (callback) has returned negative value during encoding. + */ +asn_enc_rval_t asn_encode( + const asn_codec_ctx_t *opt_codec_parameters, /* See asn_codecs.h */ + enum asn_transfer_syntax, + const struct asn_TYPE_descriptor_s *type_to_encode, + const void *structure_to_encode, + asn_app_consume_bytes_f *callback, void *callback_key); + + +/* + * A generic decoder for any supported transfer syntax. + */ +asn_dec_rval_t asn_decode( + const asn_codec_ctx_t *opt_codec_parameters, enum asn_transfer_syntax, + const struct asn_TYPE_descriptor_s *type_to_decode, + void **structure_ptr, /* Pointer to a target structure's pointer */ + const void *buffer, /* Data to be decoded */ + size_t size /* Size of that buffer */ +); + + +/* + * A callback of this type is called whenever constraint validation fails + * on some ASN.1 type. See "constraints.h" for more details on constraint + * validation. + * This callback specifies a descriptor of the ASN.1 type which failed + * the constraint check, as well as human readable message on what + * particular constraint has failed. + */ +typedef void (asn_app_constraint_failed_f)(void *application_specific_key, + const struct asn_TYPE_descriptor_s *type_descriptor_which_failed, + const void *structure_which_failed_ptr, + const char *error_message_format, ...) CC_PRINTFLIKE(4, 5); + + +#ifdef __cplusplus +} +#endif + +#include "constr_TYPE.h" /* for asn_TYPE_descriptor_t */ + +#endif /* ASN_APPLICATION_H */ diff --git a/Vendor/asn1/include/asn_bit_data.c b/Vendor/asn1/include/asn_bit_data.c new file mode 100644 index 0000000..fe4b89b --- /dev/null +++ b/Vendor/asn1/include/asn_bit_data.c @@ -0,0 +1,333 @@ +/* + * Copyright (c) 2005-2017 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include + +/* + * Create a contiguous non-refillable bit data structure. + * Can be freed by FREEMEM(). + */ +asn_bit_data_t * +asn_bit_data_new_contiguous(const void *data, size_t size_bits) { + size_t size_bytes = (size_bits + 7) / 8; + asn_bit_data_t *pd; + uint8_t *bytes; + + /* Get the extensions map */ + pd = CALLOC(1, sizeof(*pd) + size_bytes + 1); + if(!pd) { + return NULL; + } + bytes = (void *)(((char *)pd) + sizeof(*pd)); + memcpy(bytes, data, size_bytes); + bytes[size_bytes] = 0; + pd->buffer = bytes; + pd->nboff = 0; + pd->nbits = size_bits; + + return pd; +} + + +char * +asn_bit_data_string(asn_bit_data_t *pd) { + static char buf[2][32]; + static int n; + n = (n+1) % 2; + snprintf(buf[n], sizeof(buf[n]), + "{m=%" ASN_PRI_SIZE " span %" ASN_PRI_SIZE "[%" ASN_PRI_SIZE + "..%" ASN_PRI_SIZE "] (%" ASN_PRI_SIZE ")}", + pd->moved, ((uintptr_t)(pd->buffer) & 0xf), pd->nboff, pd->nbits, + pd->nbits - pd->nboff); + return buf[n]; +} + +void +asn_get_undo(asn_bit_data_t *pd, int nbits) { + if((ssize_t)pd->nboff < nbits) { + assert((ssize_t)pd->nboff < nbits); + } else { + pd->nboff -= nbits; + pd->moved -= nbits; + } +} + +/* + * Extract a small number of bits (<= 31) from the specified PER data pointer. + */ +int32_t +asn_get_few_bits(asn_bit_data_t *pd, int nbits) { + size_t off; /* Next after last bit offset */ + ssize_t nleft; /* Number of bits left in this stream */ + uint32_t accum; + const uint8_t *buf; + + if(nbits < 0) + return -1; + + nleft = pd->nbits - pd->nboff; + if(nbits > nleft) { + int32_t tailv, vhead; + if(!pd->refill || nbits > 31) return -1; + /* Accumulate unused bytes before refill */ + ASN_DEBUG("Obtain the rest %d bits (want %d)", + (int)nleft, (int)nbits); + tailv = asn_get_few_bits(pd, nleft); + if(tailv < 0) return -1; + /* Refill (replace pd contents with new data) */ + if(pd->refill(pd)) + return -1; + nbits -= nleft; + vhead = asn_get_few_bits(pd, nbits); + /* Combine the rest of previous pd with the head of new one */ + tailv = (tailv << nbits) | vhead; /* Could == -1 */ + return tailv; + } + + /* + * Normalize position indicator. + */ + if(pd->nboff >= 8) { + pd->buffer += (pd->nboff >> 3); + pd->nbits -= (pd->nboff & ~0x07); + pd->nboff &= 0x07; + } + pd->moved += nbits; + pd->nboff += nbits; + off = pd->nboff; + buf = pd->buffer; + + /* + * Extract specified number of bits. + */ + if(off <= 8) + accum = nbits ? (buf[0]) >> (8 - off) : 0; + else if(off <= 16) + accum = ((buf[0] << 8) + buf[1]) >> (16 - off); + else if(off <= 24) + accum = ((buf[0] << 16) + (buf[1] << 8) + buf[2]) >> (24 - off); + else if(off <= 31) + accum = (((uint32_t)buf[0] << 24) + (buf[1] << 16) + + (buf[2] << 8) + (buf[3])) >> (32 - off); + else if(nbits <= 31) { + asn_bit_data_t tpd = *pd; + /* Here are we with our 31-bits limit plus 1..7 bits offset. */ + asn_get_undo(&tpd, nbits); + /* The number of available bits in the stream allow + * for the following operations to take place without + * invoking the ->refill() function */ + accum = asn_get_few_bits(&tpd, nbits - 24) << 24; + accum |= asn_get_few_bits(&tpd, 24); + } else { + asn_get_undo(pd, nbits); + return -1; + } + + accum &= (((uint32_t)1 << nbits) - 1); + + ASN_DEBUG(" [PER got %2d<=%2d bits => span %d %+ld[%d..%d]:%02x (%d) => 0x%x]", + (int)nbits, (int)nleft, + (int)pd->moved, + (((long)pd->buffer) & 0xf), + (int)pd->nboff, (int)pd->nbits, + ((pd->buffer != NULL)?pd->buffer[0]:0), + (int)(pd->nbits - pd->nboff), + (int)accum); + + return accum; +} + +/* + * Extract a large number of bits from the specified PER data pointer. + */ +int +asn_get_many_bits(asn_bit_data_t *pd, uint8_t *dst, int alright, int nbits) { + int32_t value; + + if(alright && (nbits & 7)) { + /* Perform right alignment of a first few bits */ + value = asn_get_few_bits(pd, nbits & 0x07); + if(value < 0) return -1; + *dst++ = value; /* value is already right-aligned */ + nbits &= ~7; + } + + while(nbits) { + if(nbits >= 24) { + value = asn_get_few_bits(pd, 24); + if(value < 0) return -1; + *(dst++) = value >> 16; + *(dst++) = value >> 8; + *(dst++) = value; + nbits -= 24; + } else { + value = asn_get_few_bits(pd, nbits); + if(value < 0) return -1; + if(nbits & 7) { /* implies left alignment */ + value <<= 8 - (nbits & 7), + nbits += 8 - (nbits & 7); + if(nbits > 24) + *dst++ = value >> 24; + } + if(nbits > 16) + *dst++ = value >> 16; + if(nbits > 8) + *dst++ = value >> 8; + *dst++ = value; + break; + } + } + + return 0; +} + +/* + * Put a small number of bits (<= 31). + */ +int +asn_put_few_bits(asn_bit_outp_t *po, uint32_t bits, int obits) { + size_t off; /* Next after last bit offset */ + size_t omsk; /* Existing last byte meaningful bits mask */ + uint8_t *buf; + + if(obits <= 0 || obits >= 32) return obits ? -1 : 0; + + ASN_DEBUG("[PER put %d bits %x to %p+%d bits]", + obits, (int)bits, (void *)po->buffer, (int)po->nboff); + + /* + * Normalize position indicator. + */ + if(po->nboff >= 8) { + po->buffer += (po->nboff >> 3); + po->nbits -= (po->nboff & ~0x07); + po->nboff &= 0x07; + } + + /* + * Flush whole-bytes output, if necessary. + */ + if(po->nboff + obits > po->nbits) { + size_t complete_bytes; + if(!po->buffer) po->buffer = po->tmpspace; + complete_bytes = (po->buffer - po->tmpspace); + ASN_DEBUG("[PER output %ld complete + %ld]", + (long)complete_bytes, (long)po->flushed_bytes); + if(po->output(po->tmpspace, complete_bytes, po->op_key) < 0) + return -1; + if(po->nboff) + po->tmpspace[0] = po->buffer[0]; + po->buffer = po->tmpspace; + po->nbits = 8 * sizeof(po->tmpspace); + po->flushed_bytes += complete_bytes; + } + + /* + * Now, due to sizeof(tmpspace), we are guaranteed large enough space. + */ + buf = po->buffer; + omsk = ~((1 << (8 - po->nboff)) - 1); + off = (po->nboff + obits); + + /* Clear data of debris before meaningful bits */ + bits &= (((uint32_t)1 << obits) - 1); + + ASN_DEBUG("[PER out %d %u/%x (t=%d,o=%d) %x&%x=%x]", obits, + (int)bits, (int)bits, + (int)po->nboff, (int)off, + buf[0], (int)(omsk&0xff), + (int)(buf[0] & omsk)); + + if(off <= 8) /* Completely within 1 byte */ + po->nboff = off, + bits <<= (8 - off), + buf[0] = (buf[0] & omsk) | bits; + else if(off <= 16) + po->nboff = off, + bits <<= (16 - off), + buf[0] = (buf[0] & omsk) | (bits >> 8), + buf[1] = bits; + else if(off <= 24) + po->nboff = off, + bits <<= (24 - off), + buf[0] = (buf[0] & omsk) | (bits >> 16), + buf[1] = bits >> 8, + buf[2] = bits; + else if(off <= 31) + po->nboff = off, + bits <<= (32 - off), + buf[0] = (buf[0] & omsk) | (bits >> 24), + buf[1] = bits >> 16, + buf[2] = bits >> 8, + buf[3] = bits; + else { + if(asn_put_few_bits(po, bits >> (obits - 24), 24)) return -1; + if(asn_put_few_bits(po, bits, obits - 24)) return -1; + } + + ASN_DEBUG("[PER out %u/%x => %02x buf+%ld]", + (int)bits, (int)bits, buf[0], + (long)(po->buffer - po->tmpspace)); + + return 0; +} + + +/* + * Output a large number of bits. + */ +int +asn_put_many_bits(asn_bit_outp_t *po, const uint8_t *src, int nbits) { + + while(nbits) { + uint32_t value; + + if(nbits >= 24) { + value = (src[0] << 16) | (src[1] << 8) | src[2]; + src += 3; + nbits -= 24; + if(asn_put_few_bits(po, value, 24)) + return -1; + } else { + value = src[0]; + if(nbits > 8) + value = (value << 8) | src[1]; + if(nbits > 16) + value = (value << 8) | src[2]; + if(nbits & 0x07) + value >>= (8 - (nbits & 0x07)); + if(asn_put_few_bits(po, value, nbits)) + return -1; + break; + } + } + + return 0; +} + + +int +asn_put_aligned_flush(asn_bit_outp_t *po) { + uint32_t unused_bits = (0x7 & (8 - (po->nboff & 0x07))); + size_t complete_bytes = + (po->buffer ? po->buffer - po->tmpspace : 0) + ((po->nboff + 7) >> 3); + + if(unused_bits) { + po->buffer[po->nboff >> 3] &= ~0u << unused_bits; + } + + if(po->output(po->tmpspace, complete_bytes, po->op_key) < 0) { + return -1; + } else { + po->buffer = po->tmpspace; + po->nboff = 0; + po->nbits = 8 * sizeof(po->tmpspace); + po->flushed_bytes += complete_bytes; + return 0; + } +} + diff --git a/Vendor/asn1/include/asn_bit_data.h b/Vendor/asn1/include/asn_bit_data.h new file mode 100644 index 0000000..59de7af --- /dev/null +++ b/Vendor/asn1/include/asn_bit_data.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2005-2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef ASN_BIT_DATA +#define ASN_BIT_DATA + +#include /* Platform-specific types */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This structure describes a position inside an incoming PER bit stream. + */ +typedef struct asn_bit_data_s { + const uint8_t *buffer; /* Pointer to the octet stream */ + size_t nboff; /* Bit offset to the meaningful bit */ + size_t nbits; /* Number of bits in the stream */ + size_t moved; /* Number of bits moved through this bit stream */ + int (*refill)(struct asn_bit_data_s *); + void *refill_key; +} asn_bit_data_t; + +/* + * Create a contiguous non-refillable bit data structure. + * Can be freed by FREEMEM(). + */ +asn_bit_data_t *asn_bit_data_new_contiguous(const void *data, size_t size_bits); + +/* + * Extract a small number of bits (<= 31) from the specified PER data pointer. + * This function returns -1 if the specified number of bits could not be + * extracted due to EOD or other conditions. + */ +int32_t asn_get_few_bits(asn_bit_data_t *, int get_nbits); + +/* Undo the immediately preceeding "get_few_bits" operation */ +void asn_get_undo(asn_bit_data_t *, int get_nbits); + +/* + * Extract a large number of bits from the specified PER data pointer. + * This function returns -1 if the specified number of bits could not be + * extracted due to EOD or other conditions. + */ +int asn_get_many_bits(asn_bit_data_t *, uint8_t *dst, int right_align, + int get_nbits); + +/* Non-thread-safe debugging function, don't use it */ +char *asn_bit_data_string(asn_bit_data_t *); + +/* + * This structure supports forming bit output. + */ +typedef struct asn_bit_outp_s { + uint8_t *buffer; /* Pointer into the (tmpspace) */ + size_t nboff; /* Bit offset to the meaningful bit */ + size_t nbits; /* Number of bits left in (tmpspace) */ + uint8_t tmpspace[32]; /* Preliminary storage to hold data */ + int (*output)(const void *data, size_t size, void *op_key); + void *op_key; /* Key for (output) data callback */ + size_t flushed_bytes; /* Bytes already flushed through (output) */ +} asn_bit_outp_t; + +/* Output a small number of bits (<= 31) */ +int asn_put_few_bits(asn_bit_outp_t *, uint32_t bits, int obits); + +/* Output a large number of bits */ +int asn_put_many_bits(asn_bit_outp_t *, const uint8_t *src, int put_nbits); + +/* + * Flush whole bytes (0 or more) through (outper) member. + * The least significant bits which are not used are guaranteed to be set to 0. + * Returns -1 if callback returns -1. Otherwise, 0. + */ +int asn_put_aligned_flush(asn_bit_outp_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* ASN_BIT_DATA */ diff --git a/Vendor/asn1/include/asn_codecs.h b/Vendor/asn1/include/asn_codecs.h new file mode 100644 index 0000000..e75c270 --- /dev/null +++ b/Vendor/asn1/include/asn_codecs.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2003-2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef ASN_CODECS_H +#define ASN_CODECS_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct asn_TYPE_descriptor_s; /* Forward declaration */ + +/* + * This structure defines a set of parameters that may be passed + * to every ASN.1 encoder or decoder function. + * WARNING: if max_stack_size member is set, and you are calling the + * function pointers of the asn_TYPE_descriptor_t directly, + * this structure must be ALLOCATED ON THE STACK! + * If you can't always satisfy this requirement, use ber_decode(), + * xer_decode() and uper_decode() functions instead. + */ +typedef struct asn_codec_ctx_s { + /* + * Limit the decoder routines to use no (much) more stack than a given + * number of bytes. Most of decoders are stack-based, and this + * would protect against stack overflows if the number of nested + * encodings is high. + * The OCTET STRING, BIT STRING and ANY BER decoders are heap-based, + * and are safe from this kind of overflow. + * A value from getrlimit(RLIMIT_STACK) may be used to initialize + * this variable. Be careful in multithreaded environments, as the + * stack size is rather limited. + */ + size_t max_stack_size; /* 0 disables stack bounds checking */ +} asn_codec_ctx_t; + +/* + * Type of the return value of the encoding functions (der_encode, xer_encode). + */ +typedef struct asn_enc_rval_s { + /* + * Number of bytes encoded. + * -1 indicates failure to encode the structure. + * In this case, the members below this one are meaningful. + */ + ssize_t encoded; + + /* + * Members meaningful when (encoded == -1), for post mortem analysis. + */ + + /* Type which cannot be encoded */ + const struct asn_TYPE_descriptor_s *failed_type; + + /* Pointer to the structure of that type */ + const void *structure_ptr; +} asn_enc_rval_t; +#define ASN__ENCODE_FAILED do { \ + asn_enc_rval_t tmp_error; \ + tmp_error.encoded = -1; \ + tmp_error.failed_type = td; \ + tmp_error.structure_ptr = sptr; \ + ASN_DEBUG("Failed to encode element %s", td ? td->name : ""); \ + return tmp_error; \ +} while(0) +#define ASN__ENCODED_OK(rval) do { \ + rval.structure_ptr = 0; \ + rval.failed_type = 0; \ + return rval; \ +} while(0) + +/* + * Type of the return value of the decoding functions (ber_decode, xer_decode) + * + * Please note that the number of consumed bytes is ALWAYS meaningful, + * even if code==RC_FAIL. This is to indicate the number of successfully + * decoded bytes, hence providing a possibility to fail with more diagnostics + * (i.e., print the offending remainder of the buffer). + */ +enum asn_dec_rval_code_e { + RC_OK, /* Decoded successfully */ + RC_WMORE, /* More data expected, call again */ + RC_FAIL /* Failure to decode data */ +}; +typedef struct asn_dec_rval_s { + enum asn_dec_rval_code_e code; /* Result code */ + size_t consumed; /* Number of bytes consumed */ +} asn_dec_rval_t; +#define ASN__DECODE_FAILED do { \ + asn_dec_rval_t tmp_error; \ + tmp_error.code = RC_FAIL; \ + tmp_error.consumed = 0; \ + ASN_DEBUG("Failed to decode element %s", td ? td->name : ""); \ + return tmp_error; \ +} while(0) +#define ASN__DECODE_STARVED do { \ + asn_dec_rval_t tmp_error; \ + tmp_error.code = RC_WMORE; \ + tmp_error.consumed = 0; \ + return tmp_error; \ +} while(0) + +#ifdef __cplusplus +} +#endif + +#endif /* ASN_CODECS_H */ diff --git a/Vendor/asn1/include/asn_codecs_prim.c b/Vendor/asn1/include/asn_codecs_prim.c new file mode 100644 index 0000000..78448a8 --- /dev/null +++ b/Vendor/asn1/include/asn_codecs_prim.c @@ -0,0 +1,317 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include + +/* + * Decode an always-primitive type. + */ +asn_dec_rval_t +ber_decode_primitive(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, void **sptr, + const void *buf_ptr, size_t size, int tag_mode) { + ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)*sptr; + asn_dec_rval_t rval; + ber_tlv_len_t length = 0; /* =0 to avoid [incorrect] warning. */ + + /* + * If the structure is not there, allocate it. + */ + if(st == NULL) { + st = (ASN__PRIMITIVE_TYPE_t *)CALLOC(1, sizeof(*st)); + if(st == NULL) ASN__DECODE_FAILED; + *sptr = (void *)st; + } + + ASN_DEBUG("Decoding %s as plain primitive (tm=%d)", + td->name, tag_mode); + + /* + * Check tags and extract value length. + */ + rval = ber_check_tags(opt_codec_ctx, td, 0, buf_ptr, size, + tag_mode, 0, &length, 0); + if(rval.code != RC_OK) + return rval; + + ASN_DEBUG("%s length is %d bytes", td->name, (int)length); + + /* + * Make sure we have this length. + */ + buf_ptr = ((const char *)buf_ptr) + rval.consumed; + size -= rval.consumed; + if(length > (ber_tlv_len_t)size) { + rval.code = RC_WMORE; + rval.consumed = 0; + return rval; + } + + st->size = (int)length; + /* The following better be optimized away. */ + if(sizeof(st->size) != sizeof(length) + && (ber_tlv_len_t)st->size != length) { + st->size = 0; + ASN__DECODE_FAILED; + } + + st->buf = (uint8_t *)MALLOC(length + 1); + if(!st->buf) { + st->size = 0; + ASN__DECODE_FAILED; + } + + memcpy(st->buf, buf_ptr, length); + st->buf[length] = '\0'; /* Just in case */ + + rval.code = RC_OK; + rval.consumed += length; + + ASN_DEBUG("Took %ld/%ld bytes to encode %s", + (long)rval.consumed, + (long)length, td->name); + + return rval; +} + +/* + * Encode an always-primitive type using DER. + */ +asn_enc_rval_t +der_encode_primitive(const asn_TYPE_descriptor_t *td, const void *sptr, + int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_enc_rval_t erval; + const ASN__PRIMITIVE_TYPE_t *st = (const ASN__PRIMITIVE_TYPE_t *)sptr; + + ASN_DEBUG("%s %s as a primitive type (tm=%d)", + cb?"Encoding":"Estimating", td->name, tag_mode); + + erval.encoded = der_write_tags(td, st->size, tag_mode, 0, tag, + cb, app_key); + ASN_DEBUG("%s wrote tags %d", td->name, (int)erval.encoded); + if(erval.encoded == -1) { + erval.failed_type = td; + erval.structure_ptr = sptr; + return erval; + } + + if(cb && st->buf) { + if(cb(st->buf, st->size, app_key) < 0) { + erval.encoded = -1; + erval.failed_type = td; + erval.structure_ptr = sptr; + return erval; + } + } else { + assert(st->buf || st->size == 0); + } + + erval.encoded += st->size; + ASN__ENCODED_OK(erval); +} + +void +ASN__PRIMITIVE_TYPE_free(const asn_TYPE_descriptor_t *td, void *sptr, + enum asn_struct_free_method method) { + ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)sptr; + + if(!td || !sptr) + return; + + ASN_DEBUG("Freeing %s as a primitive type", td->name); + + if(st->buf) + FREEMEM(st->buf); + + switch(method) { + case ASFM_FREE_EVERYTHING: + FREEMEM(sptr); + break; + case ASFM_FREE_UNDERLYING: + break; + case ASFM_FREE_UNDERLYING_AND_RESET: + memset(sptr, 0, sizeof(ASN__PRIMITIVE_TYPE_t)); + break; + } +} + + +/* + * Local internal type passed around as an argument. + */ +struct xdp_arg_s { + const asn_TYPE_descriptor_t *type_descriptor; + void *struct_key; + xer_primitive_body_decoder_f *prim_body_decoder; + int decoded_something; + int want_more; +}; + +/* + * Since some kinds of primitive values can be encoded using value-specific + * tags (, , etc), the primitive decoder must + * be supplied with such tags to parse them as needed. + */ +static int +xer_decode__unexpected_tag(void *key, const void *chunk_buf, size_t chunk_size) { + struct xdp_arg_s *arg = (struct xdp_arg_s *)key; + enum xer_pbd_rval bret; + + /* + * The chunk_buf is guaranteed to start at '<'. + */ + assert(chunk_size && ((const char *)chunk_buf)[0] == 0x3c); + + /* + * Decoding was performed once already. Prohibit doing it again. + */ + if(arg->decoded_something) + return -1; + + bret = arg->prim_body_decoder(arg->type_descriptor, + arg->struct_key, chunk_buf, chunk_size); + switch(bret) { + case XPBD_SYSTEM_FAILURE: + case XPBD_DECODER_LIMIT: + case XPBD_BROKEN_ENCODING: + break; + case XPBD_BODY_CONSUMED: + /* Tag decoded successfully */ + arg->decoded_something = 1; + /* Fall through */ + case XPBD_NOT_BODY_IGNORE: /* Safe to proceed further */ + return 0; + } + + return -1; +} + +static ssize_t +xer_decode__primitive_body(void *key, const void *chunk_buf, size_t chunk_size, int have_more) { + struct xdp_arg_s *arg = (struct xdp_arg_s *)key; + enum xer_pbd_rval bret; + size_t lead_wsp_size; + + if(arg->decoded_something) { + if(xer_whitespace_span(chunk_buf, chunk_size) == chunk_size) { + /* + * Example: + * "123 " + * ^- chunk_buf position. + */ + return chunk_size; + } + /* + * Decoding was done once already. Prohibit doing it again. + */ + return -1; + } + + if(!have_more) { + /* + * If we've received something like "1", we can't really + * tell whether it is really `1` or `123`, until we know + * that there is no more data coming. + * The have_more argument will be set to 1 once something + * like this is available to the caller of this callback: + * "1want_more = 1; + return -1; + } + + lead_wsp_size = xer_whitespace_span(chunk_buf, chunk_size); + chunk_buf = (const char *)chunk_buf + lead_wsp_size; + chunk_size -= lead_wsp_size; + + bret = arg->prim_body_decoder(arg->type_descriptor, + arg->struct_key, chunk_buf, chunk_size); + switch(bret) { + case XPBD_SYSTEM_FAILURE: + case XPBD_DECODER_LIMIT: + case XPBD_BROKEN_ENCODING: + break; + case XPBD_BODY_CONSUMED: + /* Tag decoded successfully */ + arg->decoded_something = 1; + /* Fall through */ + case XPBD_NOT_BODY_IGNORE: /* Safe to proceed further */ + return lead_wsp_size + chunk_size; + } + + return -1; +} + + +asn_dec_rval_t +xer_decode_primitive(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, void **sptr, + size_t struct_size, const char *opt_mname, + const void *buf_ptr, size_t size, + xer_primitive_body_decoder_f *prim_body_decoder) { + const char *xml_tag = opt_mname ? opt_mname : td->xml_tag; + asn_struct_ctx_t s_ctx; + struct xdp_arg_s s_arg; + asn_dec_rval_t rc; + + /* + * Create the structure if does not exist. + */ + if(!*sptr) { + *sptr = CALLOC(1, struct_size); + if(!*sptr) ASN__DECODE_FAILED; + } + + memset(&s_ctx, 0, sizeof(s_ctx)); + s_arg.type_descriptor = td; + s_arg.struct_key = *sptr; + s_arg.prim_body_decoder = prim_body_decoder; + s_arg.decoded_something = 0; + s_arg.want_more = 0; + + rc = xer_decode_general(opt_codec_ctx, &s_ctx, &s_arg, + xml_tag, buf_ptr, size, + xer_decode__unexpected_tag, xer_decode__primitive_body); + switch(rc.code) { + case RC_OK: + if(!s_arg.decoded_something) { + char ch; + ASN_DEBUG("Primitive body is not recognized, " + "supplying empty one"); + /* + * Decoding opportunity has come and gone. + * Where's the result? + * Try to feed with empty body, see if it eats it. + */ + if(prim_body_decoder(s_arg.type_descriptor, + s_arg.struct_key, &ch, 0) + != XPBD_BODY_CONSUMED) { + /* + * This decoder does not like empty stuff. + */ + ASN__DECODE_FAILED; + } + } + break; + case RC_WMORE: + /* + * Redo the whole thing later. + * We don't have a context to save intermediate parsing state. + */ + rc.consumed = 0; + break; + case RC_FAIL: + rc.consumed = 0; + if(s_arg.want_more) + rc.code = RC_WMORE; + else + ASN__DECODE_FAILED; + break; + } + return rc; +} + diff --git a/Vendor/asn1/include/asn_codecs_prim.h b/Vendor/asn1/include/asn_codecs_prim.h new file mode 100644 index 0000000..fbc5576 --- /dev/null +++ b/Vendor/asn1/include/asn_codecs_prim.h @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 2004-2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef ASN_CODECS_PRIM_H +#define ASN_CODECS_PRIM_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct ASN__PRIMITIVE_TYPE_s { + uint8_t *buf; /* Buffer with consecutive primitive encoding bytes */ + size_t size; /* Size of the buffer */ +} ASN__PRIMITIVE_TYPE_t; /* Do not use this type directly! */ + +asn_struct_free_f ASN__PRIMITIVE_TYPE_free; +ber_type_decoder_f ber_decode_primitive; +der_type_encoder_f der_encode_primitive; + +/* + * A callback specification for the xer_decode_primitive() function below. + */ +enum xer_pbd_rval { + XPBD_SYSTEM_FAILURE, /* System failure (memory shortage, etc) */ + XPBD_DECODER_LIMIT, /* Hit some decoder limitation or deficiency */ + XPBD_BROKEN_ENCODING, /* Encoding of a primitive body is broken */ + XPBD_NOT_BODY_IGNORE, /* Not a body format, but safe to ignore */ + XPBD_BODY_CONSUMED /* Body is recognized and consumed */ +}; +typedef enum xer_pbd_rval(xer_primitive_body_decoder_f)( + const asn_TYPE_descriptor_t *td, void *struct_ptr, const void *chunk_buf, + size_t chunk_size); + +/* + * Specific function to decode simple primitive types. + * Also see xer_decode_general() in xer_decoder.h + */ +asn_dec_rval_t xer_decode_primitive( + const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *type_descriptor, void **struct_ptr, + size_t struct_size, const char *opt_mname, const void *buf_ptr, size_t size, + xer_primitive_body_decoder_f *prim_body_decoder); + +#ifdef __cplusplus +} +#endif + +#endif /* ASN_CODECS_PRIM_H */ diff --git a/Vendor/asn1/include/asn_internal.c b/Vendor/asn1/include/asn_internal.c new file mode 100644 index 0000000..91e537c --- /dev/null +++ b/Vendor/asn1/include/asn_internal.c @@ -0,0 +1,47 @@ +#include + +ssize_t +asn__format_to_callback(int (*cb)(const void *, size_t, void *key), void *key, + const char *fmt, ...) { + char scratch[64]; + char *buf = scratch; + size_t buf_size = sizeof(scratch); + int wrote; + int cb_ret; + + do { + va_list args; + va_start(args, fmt); + + wrote = vsnprintf(buf, buf_size, fmt, args); + if(wrote < (ssize_t)buf_size) { + if(wrote < 0) { + if(buf != scratch) FREEMEM(buf); + return -1; + } + break; + } + + buf_size <<= 1; + if(buf == scratch) { + buf = MALLOC(buf_size); + if(!buf) return -1; + } else { + void *p = REALLOC(buf, buf_size); + if(!p) { + FREEMEM(buf); + return -1; + } + buf = p; + } + } while(1); + + cb_ret = cb(buf, wrote, key); + if(buf != scratch) FREEMEM(buf); + if(cb_ret < 0) { + return -1; + } + + return wrote; +} + diff --git a/Vendor/asn1/include/asn_internal.h b/Vendor/asn1/include/asn_internal.h new file mode 100644 index 0000000..2736083 --- /dev/null +++ b/Vendor/asn1/include/asn_internal.h @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2003-2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +/* + * Declarations internally useful for the ASN.1 support code. + */ +#ifndef ASN_INTERNAL_H +#define ASN_INTERNAL_H +#define __EXTENSIONS__ /* for Sun */ + +#include "asn_application.h" /* Application-visible API */ + +#ifndef __NO_ASSERT_H__ /* Include assert.h only for internal use. */ +#include /* for assert() macro */ +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Environment version might be used to avoid running with the old library */ +#define ASN1C_ENVIRONMENT_VERSION 923 /* Compile-time version */ +int get_asn1c_environment_version(void); /* Run-time version */ + +#define CALLOC(nmemb, size) calloc(nmemb, size) +#define MALLOC(size) malloc(size) +#define REALLOC(oldptr, size) realloc(oldptr, size) +#define FREEMEM(ptr) free(ptr) + +#define asn_debug_indent 0 +#define ASN_DEBUG_INDENT_ADD(i) do{}while(0) + +#ifdef EMIT_ASN_DEBUG +#warning "Use ASN_EMIT_DEBUG instead of EMIT_ASN_DEBUG" +#define ASN_EMIT_DEBUG EMIT_ASN_DEBUG +#endif + +/* + * A macro for debugging the ASN.1 internals. + * You may enable or override it. + */ +#ifndef ASN_DEBUG /* If debugging code is not defined elsewhere... */ +#if ASN_EMIT_DEBUG == 1 /* And it was asked to emit this code... */ +#if __STDC_VERSION__ >= 199901L +#ifdef ASN_THREAD_SAFE +/* Thread safety requires sacrifice in output indentation: + * Retain empty definition of ASN_DEBUG_INDENT_ADD. */ +#else /* !ASN_THREAD_SAFE */ +#undef ASN_DEBUG_INDENT_ADD +#undef asn_debug_indent +int asn_debug_indent; +#define ASN_DEBUG_INDENT_ADD(i) do { asn_debug_indent += i; } while(0) +#endif /* ASN_THREAD_SAFE */ +#define ASN_DEBUG(fmt, args...) do { \ + int adi = asn_debug_indent; \ + while(adi--) fprintf(stderr, " "); \ + fprintf(stderr, fmt, ##args); \ + fprintf(stderr, " (%s:%d)\n", \ + __FILE__, __LINE__); \ + } while(0) +#else /* !C99 */ +void CC_PRINTFLIKE(1, 2) ASN_DEBUG_f(const char *fmt, ...); +#define ASN_DEBUG ASN_DEBUG_f +#endif /* C99 */ +#else /* ASN_EMIT_DEBUG != 1 */ +#if __STDC_VERSION__ >= 199901L +#define ASN_DEBUG(...) do{}while(0) +#else /* not C99 */ +static void CC_PRINTFLIKE(1, 2) ASN_DEBUG(const char *fmt, ...) { (void)fmt; } +#endif /* C99 or better */ +#endif /* ASN_EMIT_DEBUG */ +#endif /* ASN_DEBUG */ + +/* + * Print to a callback. + * The callback is expected to return negative values on error. + * 0 and positive values are treated as success. + * RETURN VALUES: + * -1: Failed to format or invoke the callback. + * >0: Size of the data that got delivered to the callback. + */ +ssize_t CC_PRINTFLIKE(3, 4) +asn__format_to_callback( + int (*callback)(const void *, size_t, void *key), void *key, + const char *fmt, ...); + +/* + * Invoke the application-supplied callback and fail, if something is wrong. + */ +#define ASN__E_cbc(buf, size) (cb((buf), (size), app_key) < 0) +#define ASN__E_CALLBACK(size, foo) \ + do { \ + if(foo) goto cb_failed; \ + er.encoded += (size); \ + } while(0) +#define ASN__CALLBACK(buf, size) ASN__E_CALLBACK(size, ASN__E_cbc(buf, size)) +#define ASN__CALLBACK2(buf1, size1, buf2, size2) \ + ASN__E_CALLBACK((size1) + (size2), \ + ASN__E_cbc(buf1, size1) || ASN__E_cbc(buf2, size2)) +#define ASN__CALLBACK3(buf1, size1, buf2, size2, buf3, size3) \ + ASN__E_CALLBACK((size1) + (size2) + (size3), \ + ASN__E_cbc(buf1, size1) || ASN__E_cbc(buf2, size2) \ + || ASN__E_cbc(buf3, size3)) + +#define ASN__TEXT_INDENT(nl, level) \ + do { \ + int tmp_level = (level); \ + int tmp_nl = ((nl) != 0); \ + int tmp_i; \ + if(tmp_nl) ASN__CALLBACK("\n", 1); \ + if(tmp_level < 0) tmp_level = 0; \ + for(tmp_i = 0; tmp_i < tmp_level; tmp_i++) ASN__CALLBACK(" ", 4); \ + } while(0) + +#define _i_INDENT(nl) do { \ + int tmp_i; \ + if((nl) && cb("\n", 1, app_key) < 0) \ + return -1; \ + for(tmp_i = 0; tmp_i < ilevel; tmp_i++) \ + if(cb(" ", 4, app_key) < 0) \ + return -1; \ + } while(0) + +/* + * Check stack against overflow, if limit is set. + */ +#define ASN__DEFAULT_STACK_MAX (30000) +static int CC_NOTUSED +ASN__STACK_OVERFLOW_CHECK(const asn_codec_ctx_t *ctx) { + if(ctx && ctx->max_stack_size) { + + /* ctx MUST be allocated on the stack */ + ptrdiff_t usedstack = ((const char *)ctx - (const char *)&ctx); + if(usedstack > 0) usedstack = -usedstack; /* grows up! */ + + /* double negative required to avoid int wrap-around */ + if(usedstack < -(ptrdiff_t)ctx->max_stack_size) { + ASN_DEBUG("Stack limit %ld reached", + (long)ctx->max_stack_size); + return -1; + } + } + return 0; +} + +#ifdef __cplusplus +} +#endif + +#endif /* ASN_INTERNAL_H */ diff --git a/Vendor/asn1/include/asn_ioc.h b/Vendor/asn1/include/asn_ioc.h new file mode 100644 index 0000000..d2fe365 --- /dev/null +++ b/Vendor/asn1/include/asn_ioc.h @@ -0,0 +1,50 @@ +/* + * Run-time support for Information Object Classes. + * Copyright (c) 2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef ASN_IOC_H +#define ASN_IOC_H + +#include /* Platform-specific types */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct asn_TYPE_descriptor_s; +struct asn_ioc_cell_s; + +/* + * X.681, #13 + */ +typedef struct asn_ioc_set_s { + size_t rows_count; + size_t columns_count; + const struct asn_ioc_cell_s *rows; +} asn_ioc_set_t; + + +typedef struct asn_ioc_cell_s { + const char *field_name; /* Is equal to corresponding column_name */ + enum { + aioc__value, + aioc__type, + aioc__open_type, + } cell_kind; + struct asn_TYPE_descriptor_s *type_descriptor; + const void *value_sptr; + struct { + size_t types_count; + struct { + unsigned choice_position; + } *types; + } open_type; +} asn_ioc_cell_t; + + +#ifdef __cplusplus +} +#endif + +#endif /* ASN_IOC_H */ diff --git a/Vendor/asn1/include/asn_random_fill.c b/Vendor/asn1/include/asn_random_fill.c new file mode 100644 index 0000000..819cf70 --- /dev/null +++ b/Vendor/asn1/include/asn_random_fill.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2017 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include + +int +asn_random_fill(const struct asn_TYPE_descriptor_s *td, void **struct_ptr, + size_t length) { + + if(td && td->op->random_fill) { + asn_random_fill_result_t res = + td->op->random_fill(td, struct_ptr, 0, length); + return (res.code == ARFILL_OK) ? 0 : -1; + } else { + return -1; + } +} + +static uintmax_t +asn__intmax_range(intmax_t lb, intmax_t ub) { + assert(lb <= ub); + if((ub < 0) == (lb < 0)) { + return ub - lb; + } else if(lb < 0) { + return 1 + ((uintmax_t)ub + (uintmax_t)-(lb + 1)); + } else { + assert(!"Unreachable"); + return 0; + } +} + +intmax_t +asn_random_between(intmax_t lb, intmax_t rb) { + if(lb == rb) { + return lb; + } else { + const uintmax_t intmax_max = ((~(uintmax_t)0) >> 1); + uintmax_t range = asn__intmax_range(lb, rb); + uintmax_t value = 0; + uintmax_t got_entropy = 0; + + assert(RAND_MAX > 0xffffff); /* Seen 7ffffffd! */ + assert(range < intmax_max); + + for(; got_entropy < range;) { + got_entropy = (got_entropy << 24) | 0xffffff; + value = (value << 24) | (random() % 0xffffff); + } + + return lb + (intmax_t)(value % (range + 1)); + } +} diff --git a/Vendor/asn1/include/asn_random_fill.h b/Vendor/asn1/include/asn_random_fill.h new file mode 100644 index 0000000..47f9b8a --- /dev/null +++ b/Vendor/asn1/include/asn_random_fill.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef ASN_RANDOM_FILL +#define ASN_RANDOM_FILL + +/* Forward declarations */ +struct asn_TYPE_descriptor_s; +struct asn_encoding_constraints_s; + +/* + * Initialize a structure with random data according to the type specification + * and optional member constraints. + * ARGUMENTS: + * (max_length) - See (approx_max_length_limit). + * (memb_constraints) - Member constraints, if exist. + * The type can be constrained differently according + * to PER and OER specifications, so we find a value + * at the intersection of these constraints. + * In case the return differs from ARFILL_OK, the (struct_ptr) contents + * and (current_length) value remain in their original state. + */ +typedef struct asn_random_fill_result_s { + enum { + ARFILL_FAILED = -1, /* System error (memory?) */ + ARFILL_OK = 0, /* Initialization succeeded */ + ARFILL_SKIPPED = 1 /* Not done due to (length?) constraint */ + } code; + size_t length; /* Approximate number of bytes created. */ +} asn_random_fill_result_t; +typedef asn_random_fill_result_t(asn_random_fill_f)( + const struct asn_TYPE_descriptor_s *td, void **struct_ptr, + const struct asn_encoding_constraints_s *memb_constraints, + size_t max_length); + +/* + * Returns 0 if the structure was properly initialized, -1 otherwise. + * The (approx_max_length_limit) specifies the approximate limit of the + * resulting structure in units closely resembling bytes. The actual result + * might be several times larger or smaller than the length limit. + */ +int asn_random_fill(const struct asn_TYPE_descriptor_s *td, void **struct_ptr, + size_t approx_max_length_limit); + +/* + * Returns a random number between min and max. + */ +intmax_t asn_random_between(intmax_t min, intmax_t max); + +#endif /* ASN_RANDOM_FILL */ diff --git a/Vendor/asn1/include/asn_system.h b/Vendor/asn1/include/asn_system.h new file mode 100644 index 0000000..fa8cf11 --- /dev/null +++ b/Vendor/asn1/include/asn_system.h @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2003-2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +/* + * Miscellaneous system-dependent types. + */ +#ifndef ASN_SYSTEM_H +#define ASN_SYSTEM_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE 1 +#endif + +#ifndef _BSD_SOURCE +#define _BSD_SOURCE /* for snprintf() on some linux systems */ +#endif + +#include /* For snprintf(3) */ +#include /* For *alloc(3) */ +#include /* For memcpy(3) */ +#include /* For size_t */ +#include /* For LONG_MAX */ +#include /* For va_start */ +#include /* for offsetof and ptrdiff_t */ + +#ifdef _WIN32 + +#include +#define snprintf _snprintf +#define vsnprintf _vsnprintf + +/* To avoid linking with ws2_32.lib, here's the definition of ntohl() */ +#define sys_ntohl(l) ((((l) << 24) & 0xff000000) \ + | (((l) << 8) & 0xff0000) \ + | (((l) >> 8) & 0xff00) \ + | ((l >> 24) & 0xff)) + +#ifdef _MSC_VER /* MSVS.Net */ +#ifndef __cplusplus +#define inline __inline +#endif +#ifndef ASSUMESTDTYPES /* Standard types have been defined elsewhere */ +#define ssize_t SSIZE_T +#if _MSC_VER < 1600 +typedef char int8_t; +typedef short int16_t; +typedef int int32_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +#else /* _MSC_VER >= 1600 */ +#include +#endif /* _MSC_VER < 1600 */ +#endif /* ASSUMESTDTYPES */ +#define WIN32_LEAN_AND_MEAN +#include +#include +#define isnan _isnan +#define finite _finite +#define copysign _copysign +#define ilogb _logb +#else /* !_MSC_VER */ +#include +#endif /* _MSC_VER */ + +#else /* !_WIN32 */ + +#if defined(__vxworks) +#include +#else /* !defined(__vxworks) */ + +#include /* C99 specifies this file */ +#include /* for ntohl() */ +#define sys_ntohl(foo) ntohl(foo) +#endif /* defined(__vxworks) */ + +#endif /* _WIN32 */ + +#if __GNUC__ >= 3 || defined(__clang__) +#define CC_ATTRIBUTE(attr) __attribute__((attr)) +#else +#define CC_ATTRIBUTE(attr) +#endif +#define CC_PRINTFLIKE(fmt, var) CC_ATTRIBUTE(format(printf, fmt, var)) +#define CC_NOTUSED CC_ATTRIBUTE(unused) +#ifndef CC_ATTR_NO_SANITIZE +#define CC_ATTR_NO_SANITIZE(what) CC_ATTRIBUTE(no_sanitize(what)) +#endif + +/* Figure out if thread safety is requested */ +#if !defined(ASN_THREAD_SAFE) && (defined(THREAD_SAFE) || defined(_REENTRANT)) +#define ASN_THREAD_SAFE +#endif /* Thread safety */ + +#ifndef offsetof /* If not defined by */ +#define offsetof(s, m) ((ptrdiff_t)&(((s *)0)->m) - (ptrdiff_t)((s *)0)) +#endif /* offsetof */ + +#ifndef MIN /* Suitable for comparing primitive types (integers) */ +#if defined(__GNUC__) +#define MIN(a,b) ({ __typeof a _a = a; __typeof b _b = b; \ + ((_a)<(_b)?(_a):(_b)); }) +#else /* !__GNUC__ */ +#define MIN(a,b) ((a)<(b)?(a):(b)) /* Unsafe variant */ +#endif /* __GNUC__ */ +#endif /* MIN */ + +#if __STDC_VERSION__ >= 199901L +#ifndef SIZE_MAX +#define SIZE_MAX ((~((size_t)0)) >> 1) +#endif + +#ifndef RSIZE_MAX /* C11, Annex K */ +#define RSIZE_MAX (SIZE_MAX >> 1) +#endif +#ifndef RSSIZE_MAX /* Halve signed size even further than unsigned */ +#define RSSIZE_MAX ((ssize_t)(RSIZE_MAX >> 1)) +#endif +#else /* Old compiler */ +#undef SIZE_MAX +#undef RSIZE_MAX +#undef RSSIZE_MAX +#define SIZE_MAX ((~((size_t)0)) >> 1) +#define RSIZE_MAX (SIZE_MAX >> 1) +#define RSSIZE_MAX ((ssize_t)(RSIZE_MAX >> 1)) +#endif + +#if __STDC_VERSION__ >= 199901L +#define ASN_PRI_SIZE "zu" +#define ASN_PRI_SSIZE "zd" +#define ASN_PRIuMAX PRIuMAX +#define ASN_PRIdMAX PRIdMAX +#else +#define ASN_PRI_SIZE "lu" +#define ASN_PRI_SSIZE "ld" +#if LLONG_MAX > LONG_MAX +#define ASN_PRIuMAX "llu" +#define ASN_PRIdMAX "lld" +#else +#define ASN_PRIuMAX "lu" +#define ASN_PRIdMAX "ld" +#endif +#endif + +#endif /* ASN_SYSTEM_H */ diff --git a/Vendor/asn1/include/ber_decoder.c b/Vendor/asn1/include/ber_decoder.c new file mode 100644 index 0000000..75d6016 --- /dev/null +++ b/Vendor/asn1/include/ber_decoder.c @@ -0,0 +1,283 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include + +#undef ADVANCE +#define ADVANCE(num_bytes) do { \ + size_t num = num_bytes; \ + ptr = ((const char *)ptr) + num; \ + size -= num; \ + consumed_myself += num; \ + } while(0) +#undef RETURN +#define RETURN(_code) do { \ + asn_dec_rval_t rval; \ + rval.code = _code; \ + if(opt_ctx) opt_ctx->step = step; /* Save context */ \ + if(_code == RC_OK || opt_ctx) \ + rval.consumed = consumed_myself; \ + else \ + rval.consumed = 0; /* Context-free */ \ + return rval; \ + } while(0) + +/* + * The BER decoder of any type. + */ +asn_dec_rval_t +ber_decode(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *type_descriptor, void **struct_ptr, + const void *ptr, size_t size) { + asn_codec_ctx_t s_codec_ctx; + + /* + * Stack checker requires that the codec context + * must be allocated on the stack. + */ + if(opt_codec_ctx) { + if(opt_codec_ctx->max_stack_size) { + s_codec_ctx = *opt_codec_ctx; + opt_codec_ctx = &s_codec_ctx; + } + } else { + /* If context is not given, be security-conscious anyway */ + memset(&s_codec_ctx, 0, sizeof(s_codec_ctx)); + s_codec_ctx.max_stack_size = ASN__DEFAULT_STACK_MAX; + opt_codec_ctx = &s_codec_ctx; + } + + /* + * Invoke type-specific decoder. + */ + return type_descriptor->op->ber_decoder(opt_codec_ctx, type_descriptor, + struct_ptr, /* Pointer to the destination structure */ + ptr, size, /* Buffer and its size */ + 0 /* Default tag mode is 0 */ + ); +} + +/* + * Check the set of >> tags matches the definition. + */ +asn_dec_rval_t +ber_check_tags(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, asn_struct_ctx_t *opt_ctx, + const void *ptr, size_t size, int tag_mode, int last_tag_form, + ber_tlv_len_t *last_length, int *opt_tlv_form) { + ssize_t consumed_myself = 0; + ssize_t tag_len; + ssize_t len_len; + ber_tlv_tag_t tlv_tag; + ber_tlv_len_t tlv_len; + ber_tlv_len_t limit_len = -1; + int expect_00_terminators = 0; + int tlv_constr = -1; /* If CHOICE, opt_tlv_form is not given */ + int step = opt_ctx ? opt_ctx->step : 0; /* Where we left previously */ + int tagno; + + /* + * Make sure we didn't exceed the maximum stack size. + */ + if(ASN__STACK_OVERFLOW_CHECK(opt_codec_ctx)) + RETURN(RC_FAIL); + + /* + * So what does all this implicit skip stuff mean? + * Imagine two types, + * A ::= [5] IMPLICIT T + * B ::= [2] EXPLICIT T + * Where T is defined as + * T ::= [4] IMPLICIT SEQUENCE { ... } + * + * Let's say, we are starting to decode type A, given the + * following TLV stream: <5> <0>. What does this mean? + * It means that the type A contains type T which is, + * in turn, empty. + * Remember though, that we are still in A. We cannot + * just pass control to the type T decoder. Why? Because + * the type T decoder expects <4> <0>, not <5> <0>. + * So, we must make sure we are going to receive <5> while + * still in A, then pass control to the T decoder, indicating + * that the tag <4> was implicitly skipped. The decoder of T + * hence will be prepared to treat <4> as valid tag, and decode + * it appropriately. + */ + + tagno = step /* Continuing where left previously */ + + (tag_mode==1?-1:0) + ; + ASN_DEBUG("ber_check_tags(%s, size=%ld, tm=%d, step=%d, tagno=%d)", + td->name, (long)size, tag_mode, step, tagno); + /* assert(td->tags_count >= 1) May not be the case for CHOICE or ANY */ + + if(tag_mode == 0 && tagno == (int)td->tags_count) { + /* + * This must be the _untagged_ ANY type, + * which outermost tag isn't known in advance. + * Fetch the tag and length separately. + */ + tag_len = ber_fetch_tag(ptr, size, &tlv_tag); + switch(tag_len) { + case -1: RETURN(RC_FAIL); + case 0: RETURN(RC_WMORE); + } + tlv_constr = BER_TLV_CONSTRUCTED(ptr); + len_len = ber_fetch_length(tlv_constr, + (const char *)ptr + tag_len, size - tag_len, &tlv_len); + switch(len_len) { + case -1: RETURN(RC_FAIL); + case 0: RETURN(RC_WMORE); + } + ASN_DEBUG("Advancing %ld in ANY case", + (long)(tag_len + len_len)); + ADVANCE(tag_len + len_len); + } else { + assert(tagno < (int)td->tags_count); /* At least one loop */ + } + for((void)tagno; tagno < (int)td->tags_count; tagno++, step++) { + + /* + * Fetch and process T from TLV. + */ + tag_len = ber_fetch_tag(ptr, size, &tlv_tag); + ASN_DEBUG("Fetching tag from {%p,%ld}: " + "len %ld, step %d, tagno %d got %s", + ptr, (long)size, + (long)tag_len, step, tagno, + ber_tlv_tag_string(tlv_tag)); + switch(tag_len) { + case -1: RETURN(RC_FAIL); + case 0: RETURN(RC_WMORE); + } + + tlv_constr = BER_TLV_CONSTRUCTED(ptr); + + /* + * If {I}, don't check anything. + * If {I,B,C}, check B and C unless we're at I. + */ + if(tag_mode != 0 && step == 0) { + /* + * We don't expect tag to match here. + * It's just because we don't know how the tag + * is supposed to look like. + */ + } else { + assert(tagno >= 0); /* Guaranteed by the code above */ + if(tlv_tag != td->tags[tagno]) { + /* + * Unexpected tag. Too bad. + */ + ASN_DEBUG("Expected: %s, " + "expectation failed (tn=%d, tm=%d)", + ber_tlv_tag_string(td->tags[tagno]), + tagno, tag_mode + ); + RETURN(RC_FAIL); + } + } + + /* + * Attention: if there are more tags expected, + * ensure that the current tag is presented + * in constructed form (it contains other tags!). + * If this one is the last one, check that the tag form + * matches the one given in descriptor. + */ + if(tagno < ((int)td->tags_count - 1)) { + if(tlv_constr == 0) { + ASN_DEBUG("tlv_constr = %d, expfail", + tlv_constr); + RETURN(RC_FAIL); + } + } else { + if(last_tag_form != tlv_constr + && last_tag_form != -1) { + ASN_DEBUG("last_tag_form %d != %d", + last_tag_form, tlv_constr); + RETURN(RC_FAIL); + } + } + + /* + * Fetch and process L from TLV. + */ + len_len = ber_fetch_length(tlv_constr, + (const char *)ptr + tag_len, size - tag_len, &tlv_len); + ASN_DEBUG("Fetching len = %ld", (long)len_len); + switch(len_len) { + case -1: RETURN(RC_FAIL); + case 0: RETURN(RC_WMORE); + } + + /* + * FIXME + * As of today, the chain of tags + * must either contain several indefinite length TLVs, + * or several definite length ones. + * No mixing is allowed. + */ + if(tlv_len == -1) { + /* + * Indefinite length. + */ + if(limit_len == -1) { + expect_00_terminators++; + } else { + ASN_DEBUG("Unexpected indefinite length " + "in a chain of definite lengths"); + RETURN(RC_FAIL); + } + ADVANCE(tag_len + len_len); + continue; + } else { + if(expect_00_terminators) { + ASN_DEBUG("Unexpected definite length " + "in a chain of indefinite lengths"); + RETURN(RC_FAIL); + } + } + + /* + * Check that multiple TLVs specify ever decreasing length, + * which is consistent. + */ + if(limit_len == -1) { + limit_len = tlv_len + tag_len + len_len; + if(limit_len < 0) { + /* Too great tlv_len value? */ + RETURN(RC_FAIL); + } + } else if(limit_len != tlv_len + tag_len + len_len) { + /* + * Inner TLV specifies length which is inconsistent + * with the outer TLV's length value. + */ + ASN_DEBUG("Outer TLV is %ld and inner is %ld", + (long)limit_len, (long)tlv_len); + RETURN(RC_FAIL); + } + + ADVANCE(tag_len + len_len); + + limit_len -= (tag_len + len_len); + if((ssize_t)size > limit_len) { + /* + * Make sure that we won't consume more bytes + * from the parent frame than the inferred limit. + */ + size = limit_len; + } + } + + if(opt_tlv_form) + *opt_tlv_form = tlv_constr; + if(expect_00_terminators) + *last_length = -expect_00_terminators; + else + *last_length = tlv_len; + + RETURN(RC_OK); +} diff --git a/Vendor/asn1/include/ber_decoder.h b/Vendor/asn1/include/ber_decoder.h new file mode 100644 index 0000000..1ac2a5e --- /dev/null +++ b/Vendor/asn1/include/ber_decoder.h @@ -0,0 +1,66 @@ +/*- + * Copyright (c) 2003-2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _BER_DECODER_H_ +#define _BER_DECODER_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct asn_TYPE_descriptor_s; /* Forward declaration */ +struct asn_codec_ctx_s; /* Forward declaration */ + +/* + * The BER decoder of any type. + * This function may be invoked directly from the application. + * Decodes BER, DER and CER data (DER and CER are different subsets of BER). + * + * NOTE: Use the der_encode() function (der_encoder.h) to produce encoding + * which is compliant with ber_decode(). + */ +asn_dec_rval_t ber_decode( + const struct asn_codec_ctx_s *opt_codec_ctx, + const struct asn_TYPE_descriptor_s *type_descriptor, + void **struct_ptr, /* Pointer to a target structure's pointer */ + const void *buffer, /* Data to be decoded */ + size_t size /* Size of that buffer */ +); + +/* + * Type of generic function which decodes the byte stream into the structure. + */ +typedef asn_dec_rval_t(ber_type_decoder_f)( + const struct asn_codec_ctx_s *opt_codec_ctx, + const struct asn_TYPE_descriptor_s *type_descriptor, void **struct_ptr, + const void *buf_ptr, size_t size, int tag_mode); + +/******************************* + * INTERNALLY USEFUL FUNCTIONS * + *******************************/ + +/* + * Check that all tags correspond to the type definition (as given in head). + * On return, last_length would contain either a non-negative length of the + * value part of the last TLV, or the negative number of expected + * "end of content" sequences. The number may only be negative if the + * head->last_tag_form is non-zero. + */ +asn_dec_rval_t ber_check_tags( + const struct asn_codec_ctx_s *opt_codec_ctx, /* codec options */ + const struct asn_TYPE_descriptor_s *type_descriptor, + asn_struct_ctx_t *opt_ctx, /* saved decoding context */ + const void *ptr, size_t size, + int tag_mode, /* {-1,0,1}: IMPLICIT, no, EXPLICIT */ + int last_tag_form, /* {-1,0:1}: any, primitive, constr */ + ber_tlv_len_t *last_length, int *opt_tlv_form /* optional tag form */ +); + +#ifdef __cplusplus +} +#endif + +#endif /* _BER_DECODER_H_ */ diff --git a/Vendor/asn1/include/ber_tlv_length.c b/Vendor/asn1/include/ber_tlv_length.c new file mode 100644 index 0000000..cfd4672 --- /dev/null +++ b/Vendor/asn1/include/ber_tlv_length.c @@ -0,0 +1,168 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include + +ssize_t +ber_fetch_length(int _is_constructed, const void *bufptr, size_t size, + ber_tlv_len_t *len_r) { + const uint8_t *buf = (const uint8_t *)bufptr; + unsigned oct; + + if(size == 0) + return 0; /* Want more */ + + oct = *(const uint8_t *)buf; + if((oct & 0x80) == 0) { + /* + * Short definite length. + */ + *len_r = oct; /* & 0x7F */ + return 1; + } else { + ber_tlv_len_t len; + size_t skipped; + + if(_is_constructed && oct == 0x80) { + *len_r = -1; /* Indefinite length */ + return 1; + } + + if(oct == 0xff) { + /* Reserved in standard for future use. */ + return -1; + } + + oct &= 0x7F; /* Leave only the 7 LS bits */ + for(len = 0, buf++, skipped = 1; + oct && (++skipped <= size); buf++, oct--) { + + /* Verify that we won't overflow. */ + if(!(len >> ((8 * sizeof(len)) - (8+1)))) { + len = (len << 8) | *buf; + } else { + /* Too large length value. */ + return -1; + } + } + + if(oct == 0) { + if(len < 0 || len > RSSIZE_MAX) { + /* Length value out of sane range. */ + return -1; + } + + *len_r = len; + return skipped; + } + + return 0; /* Want more */ + } + +} + +ssize_t +ber_skip_length(const asn_codec_ctx_t *opt_codec_ctx, + int _is_constructed, const void *ptr, size_t size) { + ber_tlv_len_t vlen; /* Length of V in TLV */ + ssize_t tl; /* Length of L in TLV */ + ssize_t ll; /* Length of L in TLV */ + size_t skip; + + /* + * Make sure we didn't exceed the maximum stack size. + */ + if(ASN__STACK_OVERFLOW_CHECK(opt_codec_ctx)) + return -1; + + /* + * Determine the size of L in TLV. + */ + ll = ber_fetch_length(_is_constructed, ptr, size, &vlen); + if(ll <= 0) return ll; + + /* + * Definite length. + */ + if(vlen >= 0) { + skip = ll + vlen; + if(skip > size) + return 0; /* Want more */ + return skip; + } + + /* + * Indefinite length! + */ + ASN_DEBUG("Skipping indefinite length"); + for(skip = ll, ptr = ((const char *)ptr) + ll, size -= ll;;) { + ber_tlv_tag_t tag; + + /* Fetch the tag */ + tl = ber_fetch_tag(ptr, size, &tag); + if(tl <= 0) return tl; + + ll = ber_skip_length(opt_codec_ctx, + BER_TLV_CONSTRUCTED(ptr), + ((const char *)ptr) + tl, size - tl); + if(ll <= 0) return ll; + + skip += tl + ll; + + /* + * This may be the end of the indefinite length structure, + * two consecutive 0 octets. + * Check if it is true. + */ + if(((const uint8_t *)ptr)[0] == 0 + && ((const uint8_t *)ptr)[1] == 0) + return skip; + + ptr = ((const char *)ptr) + tl + ll; + size -= tl + ll; + } + + /* UNREACHABLE */ +} + +size_t +der_tlv_length_serialize(ber_tlv_len_t len, void *bufp, size_t size) { + size_t required_size; /* Size of len encoding */ + uint8_t *buf = (uint8_t *)bufp; + uint8_t *end; + int i; + + if(len <= 127) { + /* Encoded in 1 octet */ + if(size) *buf = (uint8_t)len; + return 1; + } + + /* + * Compute the size of the subsequent bytes. + */ + for(required_size = 1, i = 8; i < 8 * (int)sizeof(len); i += 8) { + if(len >> i) + required_size++; + else + break; + } + + if(size <= required_size) + return required_size + 1; + + *buf++ = (uint8_t)(0x80 | required_size); /* Length of the encoding */ + + /* + * Produce the len encoding, space permitting. + */ + end = buf + required_size; + for(i -= 8; buf < end; i -= 8, buf++) + *buf = (uint8_t)(len >> i); + + return required_size + 1; +} + diff --git a/Vendor/asn1/include/ber_tlv_length.h b/Vendor/asn1/include/ber_tlv_length.h new file mode 100644 index 0000000..d1e4d48 --- /dev/null +++ b/Vendor/asn1/include/ber_tlv_length.h @@ -0,0 +1,50 @@ +/*- + * Copyright (c) 2003-2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _BER_TLV_LENGTH_H_ +#define _BER_TLV_LENGTH_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef ssize_t ber_tlv_len_t; + +/* + * This function tries to fetch the length of the BER TLV value and place it + * in *len_r. + * RETURN VALUES: + * 0: More data expected than bufptr contains. + * -1: Fatal error deciphering length. + * >0: Number of bytes used from bufptr. + * On return with >0, len_r is constrained as -1..MAX, where -1 mean + * that the value is of indefinite length. + */ +ssize_t ber_fetch_length(int _is_constructed, const void *bufptr, size_t size, + ber_tlv_len_t *len_r); + +/* + * This function expects bufptr to be positioned over L in TLV. + * It returns number of bytes occupied by L and V together, suitable + * for skipping. The function properly handles indefinite length. + * RETURN VALUES: + * Standard {-1,0,>0} convention. + */ +ssize_t ber_skip_length( + const struct asn_codec_ctx_s *opt_codec_ctx, /* optional context */ + int _is_constructed, const void *bufptr, size_t size); + +/* + * This function serializes the length (L from TLV) in DER format. + * It always returns number of bytes necessary to represent the length, + * it is a caller's responsibility to check the return value + * against the supplied buffer's size. + */ +size_t der_tlv_length_serialize(ber_tlv_len_t len, void *bufptr, size_t size); + +#ifdef __cplusplus +} +#endif + +#endif /* _BER_TLV_LENGTH_H_ */ diff --git a/Vendor/asn1/include/ber_tlv_tag.c b/Vendor/asn1/include/ber_tlv_tag.c new file mode 100644 index 0000000..4a7d732 --- /dev/null +++ b/Vendor/asn1/include/ber_tlv_tag.c @@ -0,0 +1,144 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include + +ssize_t +ber_fetch_tag(const void *ptr, size_t size, ber_tlv_tag_t *tag_r) { + ber_tlv_tag_t val; + ber_tlv_tag_t tclass; + size_t skipped; + + if(size == 0) + return 0; + + val = *(const uint8_t *)ptr; + tclass = (val >> 6); + if((val &= 0x1F) != 0x1F) { + /* + * Simple form: everything encoded in a single octet. + * Tag Class is encoded using two least significant bits. + */ + *tag_r = (val << 2) | tclass; + return 1; + } + + /* + * Each octet contains 7 bits of useful information. + * The MSB is 0 if it is the last octet of the tag. + */ + for(val = 0, ptr = ((const char *)ptr) + 1, skipped = 2; + skipped <= size; + ptr = ((const char *)ptr) + 1, skipped++) { + unsigned int oct = *(const uint8_t *)ptr; + if(oct & 0x80) { + val = (val << 7) | (oct & 0x7F); + /* + * Make sure there are at least 9 bits spare + * at the MS side of a value. + */ + if(val >> ((8 * sizeof(val)) - 9)) { + /* + * We would not be able to accomodate + * any more tag bits. + */ + return -1; + } + } else { + val = (val << 7) | oct; + *tag_r = (val << 2) | tclass; + return skipped; + } + } + + return 0; /* Want more */ +} + + +ssize_t +ber_tlv_tag_fwrite(ber_tlv_tag_t tag, FILE *f) { + char buf[sizeof("[APPLICATION ]") + 32]; + ssize_t ret; + + ret = ber_tlv_tag_snprint(tag, buf, sizeof(buf)); + if(ret >= (ssize_t)sizeof(buf) || ret < 2) { + errno = EPERM; + return -1; + } + + return fwrite(buf, 1, ret, f); +} + +ssize_t +ber_tlv_tag_snprint(ber_tlv_tag_t tag, char *buf, size_t size) { + const char *type = 0; + int ret; + + switch(tag & 0x3) { + case ASN_TAG_CLASS_UNIVERSAL: type = "UNIVERSAL "; break; + case ASN_TAG_CLASS_APPLICATION: type = "APPLICATION "; break; + case ASN_TAG_CLASS_CONTEXT: type = ""; break; + case ASN_TAG_CLASS_PRIVATE: type = "PRIVATE "; break; + } + + ret = snprintf(buf, size, "[%s%u]", type, ((unsigned)tag) >> 2); + if(ret <= 0 && size) buf[0] = '\0'; /* against broken libc's */ + + return ret; +} + +char * +ber_tlv_tag_string(ber_tlv_tag_t tag) { + static char buf[sizeof("[APPLICATION ]") + 32]; + + (void)ber_tlv_tag_snprint(tag, buf, sizeof(buf)); + + return buf; +} + + +size_t +ber_tlv_tag_serialize(ber_tlv_tag_t tag, void *bufp, size_t size) { + int tclass = BER_TAG_CLASS(tag); + ber_tlv_tag_t tval = BER_TAG_VALUE(tag); + uint8_t *buf = (uint8_t *)bufp; + uint8_t *end; + size_t required_size; + size_t i; + + if(tval <= 30) { + /* Encoded in 1 octet */ + if(size) buf[0] = (tclass << 6) | tval; + return 1; + } else if(size) { + *buf++ = (tclass << 6) | 0x1F; + size--; + } + + /* + * Compute the size of the subsequent bytes. + */ + for(required_size = 1, i = 7; i < 8 * sizeof(tval); i += 7) { + if(tval >> i) + required_size++; + else + break; + } + + if(size < required_size) + return required_size + 1; + + /* + * Fill in the buffer, space permitting. + */ + end = buf + required_size - 1; + for(i -= 7; buf < end; i -= 7, buf++) + *buf = 0x80 | ((tval >> i) & 0x7F); + *buf = (tval & 0x7F); /* Last octet without high bit */ + + return required_size + 1; +} + diff --git a/Vendor/asn1/include/ber_tlv_tag.h b/Vendor/asn1/include/ber_tlv_tag.h new file mode 100644 index 0000000..ce227ad --- /dev/null +++ b/Vendor/asn1/include/ber_tlv_tag.h @@ -0,0 +1,60 @@ +/*- + * Copyright (c) 2003-2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _BER_TLV_TAG_H_ +#define _BER_TLV_TAG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +enum asn_tag_class { + ASN_TAG_CLASS_UNIVERSAL = 0, /* 0b00 */ + ASN_TAG_CLASS_APPLICATION = 1, /* 0b01 */ + ASN_TAG_CLASS_CONTEXT = 2, /* 0b10 */ + ASN_TAG_CLASS_PRIVATE = 3 /* 0b11 */ +}; +typedef unsigned ber_tlv_tag_t; /* BER TAG from Tag-Length-Value */ + +/* + * Tag class is encoded together with tag value for optimization purposes. + */ +#define BER_TAG_CLASS(tag) ((tag) & 0x3) +#define BER_TAG_VALUE(tag) ((tag) >> 2) +#define BER_TLV_CONSTRUCTED(tagptr) (((*(const uint8_t *)tagptr)&0x20)?1:0) + +#define BER_TAGS_EQUAL(tag1, tag2) ((tag1) == (tag2)) + +/* + * Several functions for printing the TAG in the canonical form + * (i.e. "[PRIVATE 0]"). + * Return values correspond to their libc counterparts (if any). + */ +ssize_t ber_tlv_tag_snprint(ber_tlv_tag_t tag, char *buf, size_t buflen); +ssize_t ber_tlv_tag_fwrite(ber_tlv_tag_t tag, FILE *); +char *ber_tlv_tag_string(ber_tlv_tag_t tag); + + +/* + * This function tries to fetch the tag from the input stream. + * RETURN VALUES: + * 0: More data expected than bufptr contains. + * -1: Fatal error deciphering tag. + * >0: Number of bytes used from bufptr. tag_r will contain the tag. + */ +ssize_t ber_fetch_tag(const void *bufptr, size_t size, ber_tlv_tag_t *tag_r); + +/* + * This function serializes the tag (T from TLV) in BER format. + * It always returns number of bytes necessary to represent the tag, + * it is a caller's responsibility to check the return value + * against the supplied buffer's size. + */ +size_t ber_tlv_tag_serialize(ber_tlv_tag_t tag, void *bufptr, size_t size); + +#ifdef __cplusplus +} +#endif + +#endif /* _BER_TLV_TAG_H_ */ diff --git a/Vendor/asn1/include/constr_CHOICE.c b/Vendor/asn1/include/constr_CHOICE.c new file mode 100644 index 0000000..628979e --- /dev/null +++ b/Vendor/asn1/include/constr_CHOICE.c @@ -0,0 +1,1340 @@ +/* + * Copyright (c) 2003-2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include + +/* + * Number of bytes left for this structure. + * (ctx->left) indicates the number of bytes _transferred_ for the structure. + * (size) contains the number of bytes in the buffer passed. + */ +#define LEFT ((size<(size_t)ctx->left)?size:(size_t)ctx->left) + +/* + * If the subprocessor function returns with an indication that it wants + * more data, it may well be a fatal decoding problem, because the + * size is constrained by the 's L, even if the buffer size allows + * reading more data. + * For example, consider the buffer containing the following TLVs: + * ... + * The TLV length clearly indicates that one byte is expected in V, but + * if the V processor returns with "want more data" even if the buffer + * contains way more data than the V processor have seen. + */ +#define SIZE_VIOLATION (ctx->left >= 0 && (size_t)ctx->left <= size) + +/* + * This macro "eats" the part of the buffer which is definitely "consumed", + * i.e. was correctly converted into local representation or rightfully skipped. + */ +#undef ADVANCE +#define ADVANCE(num_bytes) do { \ + size_t num = num_bytes; \ + ptr = ((const char *)ptr) + num;\ + size -= num; \ + if(ctx->left >= 0) \ + ctx->left -= num; \ + consumed_myself += num; \ + } while(0) + +/* + * Switch to the next phase of parsing. + */ +#undef NEXT_PHASE +#define NEXT_PHASE(ctx) do { \ + ctx->phase++; \ + ctx->step = 0; \ + } while(0) + +/* + * Return a standardized complex structure. + */ +#undef RETURN +#define RETURN(_code) do { \ + rval.code = _code; \ + rval.consumed = consumed_myself;\ + return rval; \ + } while(0) + +/* + * See the definitions. + */ +static unsigned _fetch_present_idx(const void *struct_ptr, unsigned off, + unsigned size); +static void _set_present_idx(void *sptr, unsigned offset, unsigned size, + unsigned pres); +static const void *_get_member_ptr(const asn_TYPE_descriptor_t *, + const void *sptr, asn_TYPE_member_t **elm, + unsigned *present); + +/* + * Tags are canonically sorted in the tag to member table. + */ +static int +_search4tag(const void *ap, const void *bp) { + const asn_TYPE_tag2member_t *a = (const asn_TYPE_tag2member_t *)ap; + const asn_TYPE_tag2member_t *b = (const asn_TYPE_tag2member_t *)bp; + + int a_class = BER_TAG_CLASS(a->el_tag); + int b_class = BER_TAG_CLASS(b->el_tag); + + if(a_class == b_class) { + ber_tlv_tag_t a_value = BER_TAG_VALUE(a->el_tag); + ber_tlv_tag_t b_value = BER_TAG_VALUE(b->el_tag); + + if(a_value == b_value) + return 0; + else if(a_value < b_value) + return -1; + else + return 1; + } else if(a_class < b_class) { + return -1; + } else { + return 1; + } +} + +/* + * The decoder of the CHOICE type. + */ +asn_dec_rval_t +CHOICE_decode_ber(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, void **struct_ptr, + const void *ptr, size_t size, int tag_mode) { + /* + * Bring closer parts of structure description. + */ + const asn_CHOICE_specifics_t *specs = + (const asn_CHOICE_specifics_t *)td->specifics; + asn_TYPE_member_t *elements = td->elements; + + /* + * Parts of the structure being constructed. + */ + void *st = *struct_ptr; /* Target structure. */ + asn_struct_ctx_t *ctx; /* Decoder context */ + + ber_tlv_tag_t tlv_tag; /* T from TLV */ + ssize_t tag_len; /* Length of TLV's T */ + asn_dec_rval_t rval; /* Return code from subparsers */ + + ssize_t consumed_myself = 0; /* Consumed bytes from ptr */ + + ASN_DEBUG("Decoding %s as CHOICE", td->name); + + /* + * Create the target structure if it is not present already. + */ + if(st == 0) { + st = *struct_ptr = CALLOC(1, specs->struct_size); + if(st == 0) { + RETURN(RC_FAIL); + } + } + + /* + * Restore parsing context. + */ + ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); + + /* + * Start to parse where left previously + */ + switch(ctx->phase) { + case 0: + /* + * PHASE 0. + * Check that the set of tags associated with given structure + * perfectly fits our expectations. + */ + + if(tag_mode || td->tags_count) { + rval = ber_check_tags(opt_codec_ctx, td, ctx, ptr, size, + tag_mode, -1, &ctx->left, 0); + if(rval.code != RC_OK) { + ASN_DEBUG("%s tagging check failed: %d", + td->name, rval.code); + return rval; + } + + if(ctx->left >= 0) { + /* ?Substracted below! */ + ctx->left += rval.consumed; + } + ADVANCE(rval.consumed); + } else { + ctx->left = -1; + } + + NEXT_PHASE(ctx); + + ASN_DEBUG("Structure consumes %ld bytes, buffer %ld", + (long)ctx->left, (long)size); + + /* Fall through */ + case 1: + /* + * Fetch the T from TLV. + */ + tag_len = ber_fetch_tag(ptr, LEFT, &tlv_tag); + ASN_DEBUG("In %s CHOICE tag length %d", td->name, (int)tag_len); + switch(tag_len) { + case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); + /* Fall through */ + case -1: RETURN(RC_FAIL); + } + + do { + const asn_TYPE_tag2member_t *t2m; + asn_TYPE_tag2member_t key; + + key.el_tag = tlv_tag; + t2m = (const asn_TYPE_tag2member_t *)bsearch(&key, + specs->tag2el, specs->tag2el_count, + sizeof(specs->tag2el[0]), _search4tag); + if(t2m) { + /* + * Found the element corresponding to the tag. + */ + NEXT_PHASE(ctx); + ctx->step = t2m->el_no; + break; + } else if(specs->ext_start == -1) { + ASN_DEBUG("Unexpected tag %s " + "in non-extensible CHOICE %s", + ber_tlv_tag_string(tlv_tag), td->name); + RETURN(RC_FAIL); + } else { + /* Skip this tag */ + ssize_t skip; + + ASN_DEBUG("Skipping unknown tag %s", + ber_tlv_tag_string(tlv_tag)); + + skip = ber_skip_length(opt_codec_ctx, + BER_TLV_CONSTRUCTED(ptr), + (const char *)ptr + tag_len, + LEFT - tag_len); + + switch(skip) { + case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); + /* Fall through */ + case -1: RETURN(RC_FAIL); + } + + ADVANCE(skip + tag_len); + RETURN(RC_OK); + } + } while(0); + + case 2: + /* + * PHASE 2. + * Read in the element. + */ + do { + asn_TYPE_member_t *elm;/* CHOICE's element */ + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + + elm = &elements[ctx->step]; + + /* + * Compute the position of the member inside a structure, + * and also a type of containment (it may be contained + * as pointer or using inline inclusion). + */ + if(elm->flags & ATF_POINTER) { + /* Member is a pointer to another structure */ + memb_ptr2 = (void **)((char *)st + elm->memb_offset); + } else { + /* + * A pointer to a pointer + * holding the start of the structure + */ + memb_ptr = (char *)st + elm->memb_offset; + memb_ptr2 = &memb_ptr; + } + /* Set presence to be able to free it properly at any time */ + _set_present_idx(st, specs->pres_offset, + specs->pres_size, ctx->step + 1); + /* + * Invoke the member fetch routine according to member's type + */ + rval = elm->type->op->ber_decoder(opt_codec_ctx, elm->type, + memb_ptr2, ptr, LEFT, elm->tag_mode); + switch(rval.code) { + case RC_OK: + break; + case RC_WMORE: /* More data expected */ + if(!SIZE_VIOLATION) { + ADVANCE(rval.consumed); + RETURN(RC_WMORE); + } + RETURN(RC_FAIL); + case RC_FAIL: /* Fatal error */ + RETURN(rval.code); + } /* switch(rval) */ + + ADVANCE(rval.consumed); + } while(0); + + NEXT_PHASE(ctx); + + /* Fall through */ + case 3: + ASN_DEBUG("CHOICE %s Leftover: %ld, size = %ld, tm=%d, tc=%d", + td->name, (long)ctx->left, (long)size, + tag_mode, td->tags_count); + + if(ctx->left > 0) { + /* + * The type must be fully decoded + * by the CHOICE member-specific decoder. + */ + RETURN(RC_FAIL); + } + + if(ctx->left == -1 + && !(tag_mode || td->tags_count)) { + /* + * This is an untagged CHOICE. + * It doesn't contain nothing + * except for the member itself, including all its tags. + * The decoding is completed. + */ + NEXT_PHASE(ctx); + break; + } + + /* + * Read in the "end of data chunks"'s. + */ + while(ctx->left < 0) { + ssize_t tl; + + tl = ber_fetch_tag(ptr, LEFT, &tlv_tag); + switch(tl) { + case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); + /* Fall through */ + case -1: RETURN(RC_FAIL); + } + + /* + * Expected <0><0>... + */ + if(((const uint8_t *)ptr)[0] == 0) { + if(LEFT < 2) { + if(SIZE_VIOLATION) + RETURN(RC_FAIL); + else + RETURN(RC_WMORE); + } else if(((const uint8_t *)ptr)[1] == 0) { + /* + * Correctly finished with <0><0>. + */ + ADVANCE(2); + ctx->left++; + continue; + } + } else { + ASN_DEBUG("Unexpected continuation in %s", + td->name); + RETURN(RC_FAIL); + } + + /* UNREACHABLE */ + } + + NEXT_PHASE(ctx); + case 4: + /* No meaningful work here */ + break; + } + + RETURN(RC_OK); +} + +asn_enc_rval_t +CHOICE_encode_der(const asn_TYPE_descriptor_t *td, const void *sptr, + int tag_mode, ber_tlv_tag_t tag, asn_app_consume_bytes_f *cb, + void *app_key) { + const asn_CHOICE_specifics_t *specs = (const asn_CHOICE_specifics_t *)td->specifics; + asn_TYPE_member_t *elm; /* CHOICE element */ + asn_enc_rval_t erval; + const void *memb_ptr; + size_t computed_size = 0; + unsigned present; + + if(!sptr) ASN__ENCODE_FAILED; + + ASN_DEBUG("%s %s as CHOICE", + cb?"Encoding":"Estimating", td->name); + + present = _fetch_present_idx(sptr, + specs->pres_offset, specs->pres_size); + + /* + * If the structure was not initialized, it cannot be encoded: + * can't deduce what to encode in the choice type. + */ + if(present == 0 || present > td->elements_count) { + if(present == 0 && td->elements_count == 0) { + /* The CHOICE is empty?! */ + erval.encoded = 0; + ASN__ENCODED_OK(erval); + } + ASN__ENCODE_FAILED; + } + + /* + * Seek over the present member of the structure. + */ + elm = &td->elements[present-1]; + if(elm->flags & ATF_POINTER) { + memb_ptr = + *(const void *const *)((const char *)sptr + elm->memb_offset); + if(memb_ptr == 0) { + if(elm->optional) { + erval.encoded = 0; + ASN__ENCODED_OK(erval); + } + /* Mandatory element absent */ + ASN__ENCODE_FAILED; + } + } else { + memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); + } + + /* + * If the CHOICE itself is tagged EXPLICIT: + * T ::= [2] EXPLICIT CHOICE { ... } + * Then emit the appropriate tags. + */ + if(tag_mode == 1 || td->tags_count) { + /* + * For this, we need to pre-compute the member. + */ + ssize_t ret; + + /* Encode member with its tag */ + erval = elm->type->op->der_encoder(elm->type, memb_ptr, + elm->tag_mode, elm->tag, 0, 0); + if(erval.encoded == -1) + return erval; + + /* Encode CHOICE with parent or my own tag */ + ret = der_write_tags(td, erval.encoded, tag_mode, 1, tag, + cb, app_key); + if(ret == -1) + ASN__ENCODE_FAILED; + computed_size += ret; + } + + /* + * Encode the single underlying member. + */ + erval = elm->type->op->der_encoder(elm->type, memb_ptr, + elm->tag_mode, elm->tag, cb, app_key); + if(erval.encoded == -1) + return erval; + + ASN_DEBUG("Encoded CHOICE member in %ld bytes (+%ld)", + (long)erval.encoded, (long)computed_size); + + erval.encoded += computed_size; + + return erval; +} + +ber_tlv_tag_t +CHOICE_outmost_tag(const asn_TYPE_descriptor_t *td, const void *ptr, int tag_mode, ber_tlv_tag_t tag) { + const asn_CHOICE_specifics_t *specs = (const asn_CHOICE_specifics_t *)td->specifics; + unsigned present; + + assert(tag_mode == 0); (void)tag_mode; + assert(tag == 0); (void)tag; + + /* + * Figure out which CHOICE element is encoded. + */ + present = _fetch_present_idx(ptr, specs->pres_offset, specs->pres_size); + + if(present > 0 && present <= td->elements_count) { + const asn_TYPE_member_t *elm = &td->elements[present-1]; + const void *memb_ptr; + + if(elm->flags & ATF_POINTER) { + memb_ptr = *(const void * const *) + ((const char *)ptr + elm->memb_offset); + } else { + memb_ptr = (const void *) + ((const char *)ptr + elm->memb_offset); + } + + return asn_TYPE_outmost_tag(elm->type, memb_ptr, + elm->tag_mode, elm->tag); + } else { + return (ber_tlv_tag_t)-1; + } +} + +int +CHOICE_constraint(const asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + const asn_CHOICE_specifics_t *specs = + (const asn_CHOICE_specifics_t *)td->specifics; + unsigned present; + + if(!sptr) { + ASN__CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + /* + * Figure out which CHOICE element is encoded. + */ + present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size); + if(present > 0 && present <= td->elements_count) { + asn_TYPE_member_t *elm = &td->elements[present-1]; + const void *memb_ptr; + + if(elm->flags & ATF_POINTER) { + memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset); + if(!memb_ptr) { + if(elm->optional) + return 0; + ASN__CTFAIL(app_key, td, sptr, + "%s: mandatory CHOICE element %s absent (%s:%d)", + td->name, elm->name, __FILE__, __LINE__); + return -1; + } + } else { + memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); + } + + if(elm->encoding_constraints.general_constraints) { + return elm->encoding_constraints.general_constraints(elm->type, memb_ptr, + ctfailcb, app_key); + } else { + return elm->type->encoding_constraints.general_constraints(elm->type, + memb_ptr, ctfailcb, app_key); + } + } else { + ASN__CTFAIL(app_key, td, sptr, + "%s: no CHOICE element given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } +} + +#undef XER_ADVANCE +#define XER_ADVANCE(num_bytes) do { \ + size_t num = num_bytes; \ + buf_ptr = (const void *)(((const char *)buf_ptr) + num); \ + size -= num; \ + consumed_myself += num; \ + } while(0) + +/* + * Decode the XER (XML) data. + */ +asn_dec_rval_t +CHOICE_decode_xer(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, void **struct_ptr, + const char *opt_mname, const void *buf_ptr, size_t size) { + /* + * Bring closer parts of structure description. + */ + const asn_CHOICE_specifics_t *specs = (const asn_CHOICE_specifics_t *)td->specifics; + const char *xml_tag = opt_mname ? opt_mname : td->xml_tag; + + /* + * Parts of the structure being constructed. + */ + void *st = *struct_ptr; /* Target structure. */ + asn_struct_ctx_t *ctx; /* Decoder context */ + + asn_dec_rval_t rval; /* Return value of a decoder */ + ssize_t consumed_myself = 0; /* Consumed bytes from ptr */ + size_t edx; /* Element index */ + + /* + * Create the target structure if it is not present already. + */ + if(st == 0) { + st = *struct_ptr = CALLOC(1, specs->struct_size); + if(st == 0) RETURN(RC_FAIL); + } + + /* + * Restore parsing context. + */ + ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); + if(ctx->phase == 0 && !*xml_tag) + ctx->phase = 1; /* Skip the outer tag checking phase */ + + /* + * Phases of XER/XML processing: + * Phase 0: Check that the opening tag matches our expectations. + * Phase 1: Processing body and reacting on closing tag. + * Phase 2: Processing inner type. + * Phase 3: Only waiting for closing tag. + * Phase 4: Skipping unknown extensions. + * Phase 5: PHASED OUT + */ + for(edx = ctx->step; ctx->phase <= 4;) { + pxer_chunk_type_e ch_type; /* XER chunk type */ + ssize_t ch_size; /* Chunk size */ + xer_check_tag_e tcv; /* Tag check value */ + asn_TYPE_member_t *elm; + + /* + * Go inside the member. + */ + if(ctx->phase == 2) { + asn_dec_rval_t tmprval; + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + unsigned old_present; + + elm = &td->elements[edx]; + + if(elm->flags & ATF_POINTER) { + /* Member is a pointer to another structure */ + memb_ptr2 = (void **)((char *)st + + elm->memb_offset); + } else { + memb_ptr = (char *)st + elm->memb_offset; + memb_ptr2 = &memb_ptr; + } + + /* Start/Continue decoding the inner member */ + tmprval = elm->type->op->xer_decoder(opt_codec_ctx, + elm->type, memb_ptr2, elm->name, + buf_ptr, size); + XER_ADVANCE(tmprval.consumed); + ASN_DEBUG("XER/CHOICE: itdf: [%s] code=%d", + elm->type->name, tmprval.code); + old_present = _fetch_present_idx(st, + specs->pres_offset, specs->pres_size); + assert(old_present == 0 || old_present == edx + 1); + /* Record what we've got */ + _set_present_idx(st, + specs->pres_offset, specs->pres_size, edx + 1); + if(tmprval.code != RC_OK) + RETURN(tmprval.code); + ctx->phase = 3; + /* Fall through */ + } + + /* No need to wait for closing tag; special mode. */ + if(ctx->phase == 3 && !*xml_tag) { + ctx->phase = 5; /* Phase out */ + RETURN(RC_OK); + } + + /* + * Get the next part of the XML stream. + */ + ch_size = xer_next_token(&ctx->context, buf_ptr, size, &ch_type); + if(ch_size == -1) { + RETURN(RC_FAIL); + } else { + switch(ch_type) { + case PXER_WMORE: + RETURN(RC_WMORE); + case PXER_COMMENT: /* Got XML comment */ + case PXER_TEXT: /* Ignore free-standing text */ + XER_ADVANCE(ch_size); /* Skip silently */ + continue; + case PXER_TAG: + break; /* Check the rest down there */ + } + } + + tcv = xer_check_tag(buf_ptr, ch_size, xml_tag); + ASN_DEBUG("XER/CHOICE checked [%c%c%c%c] vs [%s], tcv=%d", + ch_size>0?((const uint8_t *)buf_ptr)[0]:'?', + ch_size>1?((const uint8_t *)buf_ptr)[1]:'?', + ch_size>2?((const uint8_t *)buf_ptr)[2]:'?', + ch_size>3?((const uint8_t *)buf_ptr)[3]:'?', + xml_tag, tcv); + + /* Skip the extensions section */ + if(ctx->phase == 4) { + ASN_DEBUG("skip_unknown(%d, %ld)", + tcv, (long)ctx->left); + switch(xer_skip_unknown(tcv, &ctx->left)) { + case -1: + ctx->phase = 5; + RETURN(RC_FAIL); + case 1: + ctx->phase = 3; + /* Fall through */ + case 0: + XER_ADVANCE(ch_size); + continue; + case 2: + ctx->phase = 3; + break; + } + } + + switch(tcv) { + case XCT_BOTH: + break; /* No CHOICE? */ + case XCT_CLOSING: + if(ctx->phase != 3) + break; + XER_ADVANCE(ch_size); + ctx->phase = 5; /* Phase out */ + RETURN(RC_OK); + case XCT_OPENING: + if(ctx->phase == 0) { + XER_ADVANCE(ch_size); + ctx->phase = 1; /* Processing body phase */ + continue; + } + /* Fall through */ + case XCT_UNKNOWN_OP: + case XCT_UNKNOWN_BO: + + if(ctx->phase != 1) + break; /* Really unexpected */ + + /* + * Search which inner member corresponds to this tag. + */ + for(edx = 0; edx < td->elements_count; edx++) { + elm = &td->elements[edx]; + tcv = xer_check_tag(buf_ptr,ch_size,elm->name); + switch(tcv) { + case XCT_BOTH: + case XCT_OPENING: + /* + * Process this member. + */ + ctx->step = edx; + ctx->phase = 2; + break; + case XCT_UNKNOWN_OP: + case XCT_UNKNOWN_BO: + continue; + default: + edx = td->elements_count; + break; /* Phase out */ + } + break; + } + if(edx != td->elements_count) + continue; + + /* It is expected extension */ + if(specs->ext_start != -1) { + ASN_DEBUG("Got anticipated extension"); + /* + * Check for (XCT_BOTH or XCT_UNKNOWN_BO) + * By using a mask. Only record a pure + * tags. + */ + if(tcv & XCT_CLOSING) { + /* Found without body */ + ctx->phase = 3; /* Terminating */ + } else { + ctx->left = 1; + ctx->phase = 4; /* Skip ...'s */ + } + XER_ADVANCE(ch_size); + continue; + } + + /* Fall through */ + default: + break; + } + + ASN_DEBUG("Unexpected XML tag [%c%c%c%c] in CHOICE [%s]" + " (ph=%d, tag=%s)", + ch_size>0?((const uint8_t *)buf_ptr)[0]:'?', + ch_size>1?((const uint8_t *)buf_ptr)[1]:'?', + ch_size>2?((const uint8_t *)buf_ptr)[2]:'?', + ch_size>3?((const uint8_t *)buf_ptr)[3]:'?', + td->name, ctx->phase, xml_tag); + break; + } + + ctx->phase = 5; /* Phase out, just in case */ + RETURN(RC_FAIL); +} + + +asn_enc_rval_t +CHOICE_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, + enum xer_encoder_flags_e flags, asn_app_consume_bytes_f *cb, + void *app_key) { + const asn_CHOICE_specifics_t *specs = + (const asn_CHOICE_specifics_t *)td->specifics; + asn_enc_rval_t er; + unsigned present; + + if(!sptr) + ASN__ENCODE_FAILED; + + /* + * Figure out which CHOICE element is encoded. + */ + present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size); + + if(present == 0 || present > td->elements_count) { + ASN__ENCODE_FAILED; + } else { + asn_enc_rval_t tmper; + asn_TYPE_member_t *elm = &td->elements[present-1]; + const void *memb_ptr; + const char *mname = elm->name; + unsigned int mlen = strlen(mname); + + if(elm->flags & ATF_POINTER) { + memb_ptr = + *(const void *const *)((const char *)sptr + elm->memb_offset); + if(!memb_ptr) ASN__ENCODE_FAILED; + } else { + memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); + } + + er.encoded = 0; + + if(!(flags & XER_F_CANONICAL)) ASN__TEXT_INDENT(1, ilevel); + ASN__CALLBACK3("<", 1, mname, mlen, ">", 1); + + tmper = elm->type->op->xer_encoder(elm->type, memb_ptr, + ilevel + 1, flags, cb, app_key); + if(tmper.encoded == -1) return tmper; + er.encoded += tmper.encoded; + + ASN__CALLBACK3("", 1); + } + + if(!(flags & XER_F_CANONICAL)) ASN__TEXT_INDENT(1, ilevel - 1); + + ASN__ENCODED_OK(er); +cb_failed: + ASN__ENCODE_FAILED; +} + +asn_dec_rval_t +CHOICE_decode_uper(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, + const asn_per_constraints_t *constraints, void **sptr, + asn_per_data_t *pd) { + const asn_CHOICE_specifics_t *specs = + (const asn_CHOICE_specifics_t *)td->specifics; + asn_dec_rval_t rv; + const asn_per_constraint_t *ct; + asn_TYPE_member_t *elm; /* CHOICE's element */ + void *memb_ptr; + void **memb_ptr2; + void *st = *sptr; + int value; + + if(ASN__STACK_OVERFLOW_CHECK(opt_codec_ctx)) + ASN__DECODE_FAILED; + + /* + * Create the target structure if it is not present already. + */ + if(!st) { + st = *sptr = CALLOC(1, specs->struct_size); + if(!st) ASN__DECODE_FAILED; + } + + if(constraints) ct = &constraints->value; + else if(td->encoding_constraints.per_constraints) ct = &td->encoding_constraints.per_constraints->value; + else ct = 0; + + if(ct && ct->flags & APC_EXTENSIBLE) { + value = per_get_few_bits(pd, 1); + if(value < 0) ASN__DECODE_STARVED; + if(value) ct = 0; /* Not restricted */ + } + + if(ct && ct->range_bits >= 0) { + value = per_get_few_bits(pd, ct->range_bits); + if(value < 0) ASN__DECODE_STARVED; + ASN_DEBUG("CHOICE %s got index %d in range %d", + td->name, value, ct->range_bits); + if(value > ct->upper_bound) + ASN__DECODE_FAILED; + } else { + if(specs->ext_start == -1) + ASN__DECODE_FAILED; + value = uper_get_nsnnwn(pd); + if(value < 0) ASN__DECODE_STARVED; + value += specs->ext_start; + if((unsigned)value >= td->elements_count) + ASN__DECODE_FAILED; + } + + /* Adjust if canonical order is different from natural order */ + if(specs->from_canonical_order) { + ASN_DEBUG("CHOICE presence from wire %d", value); + value = specs->from_canonical_order[value]; + ASN_DEBUG("CHOICE presence index effective %d", value); + } + + /* Set presence to be able to free it later */ + _set_present_idx(st, specs->pres_offset, specs->pres_size, value + 1); + + elm = &td->elements[value]; + if(elm->flags & ATF_POINTER) { + /* Member is a pointer to another structure */ + memb_ptr2 = (void **)((char *)st + elm->memb_offset); + } else { + memb_ptr = (char *)st + elm->memb_offset; + memb_ptr2 = &memb_ptr; + } + ASN_DEBUG("Discovered CHOICE %s encodes %s", td->name, elm->name); + + if(ct && ct->range_bits >= 0) { + rv = elm->type->op->uper_decoder(opt_codec_ctx, elm->type, + elm->encoding_constraints.per_constraints, memb_ptr2, pd); + } else { + rv = uper_open_type_get(opt_codec_ctx, elm->type, + elm->encoding_constraints.per_constraints, memb_ptr2, pd); + } + + if(rv.code != RC_OK) + ASN_DEBUG("Failed to decode %s in %s (CHOICE) %d", + elm->name, td->name, rv.code); + return rv; +} + +asn_enc_rval_t +CHOICE_encode_uper(const asn_TYPE_descriptor_t *td, + const asn_per_constraints_t *constraints, const void *sptr, + asn_per_outp_t *po) { + const asn_CHOICE_specifics_t *specs = (const asn_CHOICE_specifics_t *)td->specifics; + asn_TYPE_member_t *elm; /* CHOICE's element */ + const asn_per_constraint_t *ct; + const void *memb_ptr; + unsigned present; + int present_enc; + + if(!sptr) ASN__ENCODE_FAILED; + + ASN_DEBUG("Encoding %s as CHOICE", td->name); + + if(constraints) ct = &constraints->value; + else if(td->encoding_constraints.per_constraints) + ct = &td->encoding_constraints.per_constraints->value; + else ct = 0; + + present = _fetch_present_idx(sptr, specs->pres_offset, specs->pres_size); + + /* + * If the structure was not initialized properly, it cannot be encoded: + * can't deduce what to encode in the choice type. + */ + if(present == 0 || present > td->elements_count) + ASN__ENCODE_FAILED; + else + present--; + + ASN_DEBUG("Encoding %s CHOICE element %d", td->name, present); + + /* Adjust if canonical order is different from natural order */ + if(specs->to_canonical_order) + present_enc = specs->to_canonical_order[present]; + else + present_enc = present; + + if(ct && ct->range_bits >= 0) { + if(present_enc < ct->lower_bound + || present_enc > ct->upper_bound) { + if(ct->flags & APC_EXTENSIBLE) { + ASN_DEBUG( + "CHOICE member %d (enc %d) is an extension (%ld..%ld)", + present, present_enc, ct->lower_bound, ct->upper_bound); + if(per_put_few_bits(po, 1, 1)) + ASN__ENCODE_FAILED; + } else { + ASN__ENCODE_FAILED; + } + ct = 0; + } + } + if(ct && ct->flags & APC_EXTENSIBLE) { + ASN_DEBUG("CHOICE member %d (enc %d) is not an extension (%ld..%ld)", + present, present_enc, ct->lower_bound, ct->upper_bound); + if(per_put_few_bits(po, 0, 1)) + ASN__ENCODE_FAILED; + } + + + elm = &td->elements[present]; + ASN_DEBUG("CHOICE member \"%s\" %d (as %d)", elm->name, present, + present_enc); + if(elm->flags & ATF_POINTER) { + /* Member is a pointer to another structure */ + memb_ptr = + *(const void *const *)((const char *)sptr + elm->memb_offset); + if(!memb_ptr) ASN__ENCODE_FAILED; + } else { + memb_ptr = (const char *)sptr + elm->memb_offset; + } + + if(ct && ct->range_bits >= 0) { + if(per_put_few_bits(po, present_enc, ct->range_bits)) + ASN__ENCODE_FAILED; + + return elm->type->op->uper_encoder( + elm->type, elm->encoding_constraints.per_constraints, memb_ptr, po); + } else { + asn_enc_rval_t rval; + if(specs->ext_start == -1) ASN__ENCODE_FAILED; + if(uper_put_nsnnwn(po, present_enc - specs->ext_start)) + ASN__ENCODE_FAILED; + if(uper_open_type_put(elm->type, + elm->encoding_constraints.per_constraints, + memb_ptr, po)) + ASN__ENCODE_FAILED; + rval.encoded = 0; + ASN__ENCODED_OK(rval); + } +} + + +int +CHOICE_print(const asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, + asn_app_consume_bytes_f *cb, void *app_key) { + const asn_CHOICE_specifics_t *specs = (const asn_CHOICE_specifics_t *)td->specifics; + unsigned present; + + if(!sptr) return (cb("", 8, app_key) < 0) ? -1 : 0; + + /* + * Figure out which CHOICE element is encoded. + */ + present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size); + + /* + * Print that element. + */ + if(present > 0 && present <= td->elements_count) { + asn_TYPE_member_t *elm = &td->elements[present-1]; + const void *memb_ptr; + + if(elm->flags & ATF_POINTER) { + memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset); + if(!memb_ptr) return (cb("", 8, app_key) < 0) ? -1 : 0; + } else { + memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); + } + + /* Print member's name and stuff */ + if(0) { + if(cb(elm->name, strlen(elm->name), app_key) < 0 + || cb(": ", 2, app_key) < 0) + return -1; + } + + return elm->type->op->print_struct(elm->type, memb_ptr, ilevel, + cb, app_key); + } else { + return (cb("", 8, app_key) < 0) ? -1 : 0; + } +} + +void +CHOICE_free(const asn_TYPE_descriptor_t *td, void *ptr, + enum asn_struct_free_method method) { + const asn_CHOICE_specifics_t *specs = + (const asn_CHOICE_specifics_t *)td->specifics; + unsigned present; + + if(!td || !ptr) + return; + + ASN_DEBUG("Freeing %s as CHOICE", td->name); + + /* + * Figure out which CHOICE element is encoded. + */ + present = _fetch_present_idx(ptr, specs->pres_offset, specs->pres_size); + + /* + * Free that element. + */ + if(present > 0 && present <= td->elements_count) { + asn_TYPE_member_t *elm = &td->elements[present-1]; + void *memb_ptr; + + if(elm->flags & ATF_POINTER) { + memb_ptr = *(void **)((char *)ptr + elm->memb_offset); + if(memb_ptr) + ASN_STRUCT_FREE(*elm->type, memb_ptr); + } else { + memb_ptr = (void *)((char *)ptr + elm->memb_offset); + ASN_STRUCT_FREE_CONTENTS_ONLY(*elm->type, memb_ptr); + } + } + + switch(method) { + case ASFM_FREE_EVERYTHING: + FREEMEM(ptr); + break; + case ASFM_FREE_UNDERLYING: + break; + case ASFM_FREE_UNDERLYING_AND_RESET: + memset(ptr, 0, specs->struct_size); + break; + } +} + + +/* + * The following functions functions offer protection against -fshort-enums, + * compatible with little- and big-endian machines. + * If assertion is triggered, either disable -fshort-enums, or add an entry + * here with the ->pres_size of your target stracture. + * Unless the target structure is packed, the ".present" member + * is guaranteed to be aligned properly. ASN.1 compiler itself does not + * produce packed code. + */ +static unsigned +_fetch_present_idx(const void *struct_ptr, unsigned pres_offset, + unsigned pres_size) { + const void *present_ptr; + unsigned present; + + present_ptr = ((const char *)struct_ptr) + pres_offset; + + switch(pres_size) { + case sizeof(int): present = *(const unsigned int *)present_ptr; break; + case sizeof(short): present = *(const unsigned short *)present_ptr; break; + case sizeof(char): present = *(const unsigned char *)present_ptr; break; + default: + /* ANSI C mandates enum to be equivalent to integer */ + assert(pres_size != sizeof(int)); + return 0; /* If not aborted, pass back safe value */ + } + + return present; +} + +static void +_set_present_idx(void *struct_ptr, unsigned pres_offset, unsigned pres_size, + unsigned present) { + void *present_ptr; + present_ptr = ((char *)struct_ptr) + pres_offset; + + switch(pres_size) { + case sizeof(int): *(unsigned int *)present_ptr = present; break; + case sizeof(short): *(unsigned short *)present_ptr = present; break; + case sizeof(char): *(unsigned char *)present_ptr = present; break; + default: + /* ANSI C mandates enum to be equivalent to integer */ + assert(pres_size != sizeof(int)); + } +} + +static const void * +_get_member_ptr(const asn_TYPE_descriptor_t *td, const void *sptr, + asn_TYPE_member_t **elm_ptr, unsigned *present_out) { + const asn_CHOICE_specifics_t *specs = + (const asn_CHOICE_specifics_t *)td->specifics; + unsigned present; + + if(!sptr) { + *elm_ptr = NULL; + *present_out = 0; + return NULL; + } + + /* + * Figure out which CHOICE element is encoded. + */ + present = _fetch_present_idx(sptr, specs->pres_offset, specs->pres_size); + *present_out = present; + + /* + * The presence index is intentionally 1-based to avoid + * treating zeroed structure as a valid one. + */ + if(present > 0 && present <= td->elements_count) { + asn_TYPE_member_t *const elm = &td->elements[present - 1]; + const void *memb_ptr; + + if(elm->flags & ATF_POINTER) { + memb_ptr = + *(const void *const *)((const char *)sptr + elm->memb_offset); + } else { + memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); + } + *elm_ptr = elm; + return memb_ptr; + } else { + *elm_ptr = NULL; + return NULL; + } + +} + +int +CHOICE_compare(const asn_TYPE_descriptor_t *td, const void *aptr, const void *bptr) { + asn_TYPE_member_t *aelm; + asn_TYPE_member_t *belm; + unsigned apresent = 0; + unsigned bpresent = 0; + const void *amember = _get_member_ptr(td, aptr, &aelm, &apresent); + const void *bmember = _get_member_ptr(td, bptr, &belm, &bpresent); + + if(amember && bmember) { + if(apresent == bpresent) { + assert(aelm == belm); + return aelm->type->op->compare_struct(aelm->type, amember, bmember); + } else if(apresent < bpresent) { + return -1; + } else { + return 1; + } + } else if(!amember) { + return -1; + } else { + return 1; + } +} + +/* + * Return the 1-based choice variant presence index. + * Returns 0 in case of error. + */ +unsigned +CHOICE_variant_get_presence(const asn_TYPE_descriptor_t *td, const void *sptr) { + const asn_CHOICE_specifics_t *specs = + (const asn_CHOICE_specifics_t *)td->specifics; + return _fetch_present_idx(sptr, specs->pres_offset, specs->pres_size); +} + +/* + * Sets or resets the 1-based choice variant presence index. + * In case a previous index is not zero, the currently selected structure + * member is freed and zeroed-out first. + * Returns 0 on success and -1 on error. + */ +int +CHOICE_variant_set_presence(const asn_TYPE_descriptor_t *td, void *sptr, + unsigned present) { + const asn_CHOICE_specifics_t *specs = + (const asn_CHOICE_specifics_t *)td->specifics; + unsigned old_present; + + if(!sptr) { + return -1; + } + + if(present > td->elements_count) + return -1; + + old_present = + _fetch_present_idx(sptr, specs->pres_offset, specs->pres_size); + if(present == old_present) + return 0; + + if(old_present != 0) { + assert(old_present <= td->elements_count); + ASN_STRUCT_RESET(*td, sptr); + } + + _set_present_idx(sptr, specs->pres_offset, specs->pres_size, present); + + return 0; +} + + +asn_random_fill_result_t +CHOICE_random_fill(const asn_TYPE_descriptor_t *td, void **sptr, + const asn_encoding_constraints_t *constr, + size_t max_length) { + const asn_CHOICE_specifics_t *specs = + (const asn_CHOICE_specifics_t *)td->specifics; + asn_random_fill_result_t res; + asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0}; + asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0}; + const asn_TYPE_member_t *elm; + unsigned present; + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + void *st = *sptr; + + if(max_length == 0) return result_skipped; + + (void)constr; + + if(st == NULL) { + st = CALLOC(1, specs->struct_size); + if(st == NULL) { + return result_failed; + } + } + + present = asn_random_between(1, td->elements_count); + elm = &td->elements[present - 1]; + + if(elm->flags & ATF_POINTER) { + /* Member is a pointer to another structure */ + memb_ptr2 = (void **)((char *)st + elm->memb_offset); + } else { + memb_ptr = (char *)st + elm->memb_offset; + memb_ptr2 = &memb_ptr; + } + + res = elm->type->op->random_fill(elm->type, memb_ptr2, + &elm->encoding_constraints, max_length); + _set_present_idx(st, specs->pres_offset, specs->pres_size, present); + if(res.code == ARFILL_OK) { + *sptr = st; + } else { + if(st == *sptr) { + ASN_STRUCT_RESET(*td, st); + } else { + ASN_STRUCT_FREE(*td, st); + } + } + + return res; +} + + +asn_TYPE_operation_t asn_OP_CHOICE = { + CHOICE_free, + CHOICE_print, + CHOICE_compare, + CHOICE_decode_ber, + CHOICE_encode_der, + CHOICE_decode_xer, + CHOICE_encode_xer, +#ifdef ASN_DISABLE_OER_SUPPORT + 0, + 0, +#else + CHOICE_decode_oer, + CHOICE_encode_oer, +#endif /* ASN_DISABLE_OER_SUPPORT */ +#ifdef ASN_DISABLE_PER_SUPPORT + 0, + 0, +#else + CHOICE_decode_uper, + CHOICE_encode_uper, +#endif /* ASN_DISABLE_PER_SUPPORT */ + CHOICE_random_fill, + CHOICE_outmost_tag +}; diff --git a/Vendor/asn1/include/constr_CHOICE.h b/Vendor/asn1/include/constr_CHOICE.h new file mode 100644 index 0000000..7649480 --- /dev/null +++ b/Vendor/asn1/include/constr_CHOICE.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2003-2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _CONSTR_CHOICE_H_ +#define _CONSTR_CHOICE_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct asn_CHOICE_specifics_s { + /* + * Target structure description. + */ + unsigned struct_size; /* Size of the target structure. */ + unsigned ctx_offset; /* Offset of the asn_codec_ctx_t member */ + unsigned pres_offset; /* Identifier of the present member */ + unsigned pres_size; /* Size of the identifier (enum) */ + + /* + * Tags to members mapping table. + */ + const asn_TYPE_tag2member_t *tag2el; + unsigned tag2el_count; + + /* Canonical ordering of CHOICE elements, for PER */ + const unsigned *to_canonical_order; + const unsigned *from_canonical_order; + + /* + * Extensions-related stuff. + */ + signed ext_start; /* First member of extensions, or -1 */ +} asn_CHOICE_specifics_t; + +/* + * A set specialized functions dealing with the CHOICE type. + */ +asn_struct_free_f CHOICE_free; +asn_struct_print_f CHOICE_print; +asn_struct_compare_f CHOICE_compare; +asn_constr_check_f CHOICE_constraint; +ber_type_decoder_f CHOICE_decode_ber; +der_type_encoder_f CHOICE_encode_der; +xer_type_decoder_f CHOICE_decode_xer; +xer_type_encoder_f CHOICE_encode_xer; +oer_type_decoder_f CHOICE_decode_oer; +oer_type_encoder_f CHOICE_encode_oer; +per_type_decoder_f CHOICE_decode_uper; +per_type_encoder_f CHOICE_encode_uper; +asn_outmost_tag_f CHOICE_outmost_tag; +asn_random_fill_f CHOICE_random_fill; +extern asn_TYPE_operation_t asn_OP_CHOICE; + +/* + * Return the 1-based choice variant presence index. + * Returns 0 in case of error. + */ +unsigned CHOICE_variant_get_presence(const asn_TYPE_descriptor_t *td, + const void *structure_ptr); + +/* + * Sets or resets the 1-based choice variant presence index. + * In case a previous index is not zero, the currently selected structure + * member is freed and zeroed-out first. + * Returns 0 on success and -1 on error. + */ +int CHOICE_variant_set_presence(const asn_TYPE_descriptor_t *td, + void *structure_ptr, unsigned present); + +#ifdef __cplusplus +} +#endif + +#endif /* _CONSTR_CHOICE_H_ */ diff --git a/Vendor/asn1/include/constr_CHOICE_oer.c b/Vendor/asn1/include/constr_CHOICE_oer.c new file mode 100644 index 0000000..6480a96 --- /dev/null +++ b/Vendor/asn1/include/constr_CHOICE_oer.c @@ -0,0 +1,380 @@ +/* + * Copyright (c) 2017 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef ASN_DISABLE_OER_SUPPORT + +#include +#include +#include + +/* + * Return a standardized complex structure. + */ +#undef RETURN +#define RETURN(_code) \ + do { \ + asn_dec_rval_t rval; \ + rval.code = _code; \ + rval.consumed = consumed_myself; \ + return rval; \ + } while(0) + +#undef ADVANCE +#define ADVANCE(num_bytes) \ + do { \ + size_t num = num_bytes; \ + ptr = ((const char *)ptr) + num; \ + size -= num; \ + consumed_myself += num; \ + } while(0) + +/* + * Switch to the next phase of parsing. + */ +#undef NEXT_PHASE +#define NEXT_PHASE(ctx) \ + do { \ + ctx->phase++; \ + ctx->step = 0; \ + } while(0) +#undef SET_PHASE +#define SET_PHASE(ctx, value) \ + do { \ + ctx->phase = value; \ + ctx->step = 0; \ + } while(0) + +/* + * Tags are canonically sorted in the tag to member table. + */ +static int +_search4tag(const void *ap, const void *bp) { + const asn_TYPE_tag2member_t *a = (const asn_TYPE_tag2member_t *)ap; + const asn_TYPE_tag2member_t *b = (const asn_TYPE_tag2member_t *)bp; + + int a_class = BER_TAG_CLASS(a->el_tag); + int b_class = BER_TAG_CLASS(b->el_tag); + + if(a_class == b_class) { + ber_tlv_tag_t a_value = BER_TAG_VALUE(a->el_tag); + ber_tlv_tag_t b_value = BER_TAG_VALUE(b->el_tag); + + if(a_value == b_value) + return 0; + else if(a_value < b_value) + return -1; + else + return 1; + } else if(a_class < b_class) { + return -1; + } else { + return 1; + } +} + +/* + * X.696 (08/2015) #8.7 Encoding of tags + */ +static ssize_t +oer_fetch_tag(const void *ptr, size_t size, ber_tlv_tag_t *tag_r) { + ber_tlv_tag_t val; + ber_tlv_tag_t tclass; + size_t skipped; + + if(size == 0) + return 0; + + val = *(const uint8_t *)ptr; + tclass = (val >> 6); + if((val & 0x3F) != 0x3F) { + /* #8.7.1 */ + *tag_r = ((val & 0x3F) << 2) | tclass; + return 1; + } + + /* + * Each octet contains 7 bits of useful information. + * The MSB is 0 if it is the last octet of the tag. + */ + for(val = 0, ptr = ((const char *)ptr) + 1, skipped = 2; skipped <= size; + ptr = ((const char *)ptr) + 1, skipped++) { + unsigned int oct = *(const uint8_t *)ptr; + if(oct & 0x80) { + val = (val << 7) | (oct & 0x7F); + /* + * Make sure there are at least 9 bits spare + * at the MS side of a value. + */ + if(val >> ((8 * sizeof(val)) - 9)) { + /* + * We would not be able to accomodate + * any more tag bits. + */ + return -1; + } + } else { + val = (val << 7) | oct; + *tag_r = (val << 2) | tclass; + return skipped; + } + } + + return 0; /* Want more */ +} + +asn_dec_rval_t +CHOICE_decode_oer(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, + const asn_oer_constraints_t *constraints, void **struct_ptr, + const void *ptr, size_t size) { + /* + * Bring closer parts of structure description. + */ + const asn_CHOICE_specifics_t *specs = + (const asn_CHOICE_specifics_t *)td->specifics; + asn_TYPE_member_t *elements = td->elements; + + /* + * Parts of the structure being constructed. + */ + void *st = *struct_ptr; /* Target structure. */ + asn_struct_ctx_t *ctx; /* Decoder context */ + + ssize_t consumed_myself = 0; /* Consumed bytes from ptr */ + + (void)constraints; + + ASN_DEBUG("Decoding %s as CHOICE", td->name); + + /* + * Create the target structure if it is not present already. + */ + if(st == 0) { + st = *struct_ptr = CALLOC(1, specs->struct_size); + if(st == 0) { + RETURN(RC_FAIL); + } + } + + /* + * Restore parsing context. + */ + ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); + switch(ctx->phase) { + case 0: { + /* + * Discover the tag. + */ + ber_tlv_tag_t tlv_tag; /* T from TLV */ + ssize_t tag_len; /* Length of TLV's T */ + + tag_len = oer_fetch_tag(ptr, size, &tlv_tag); + switch(tag_len) { + case 0: + ASN__DECODE_STARVED; + case -1: + ASN__DECODE_FAILED; + } + + do { + const asn_TYPE_tag2member_t *t2m; + asn_TYPE_tag2member_t key = {0, 0, 0, 0}; + key.el_tag = tlv_tag; + + t2m = (const asn_TYPE_tag2member_t *)bsearch( + &key, specs->tag2el, specs->tag2el_count, + sizeof(specs->tag2el[0]), _search4tag); + if(t2m) { + /* + * Found the element corresponding to the tag. + */ + NEXT_PHASE(ctx); + ctx->step = t2m->el_no; + break; + } else if(specs->ext_start == -1) { + ASN_DEBUG( + "Unexpected tag %s " + "in non-extensible CHOICE %s", + ber_tlv_tag_string(tlv_tag), td->name); + RETURN(RC_FAIL); + } else { + /* Skip open type extension */ + ASN_DEBUG( + "Not implemented skipping open type extension for tag %s", + ber_tlv_tag_string(tlv_tag)); + RETURN(RC_FAIL); + } + } while(0); + + + ADVANCE(tag_len); + } + /* Fall through */ + case 1: { + asn_TYPE_member_t *elm = &elements[ctx->step]; /* CHOICE's element */ + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + asn_dec_rval_t rval; + + /* + * Compute the position of the member inside a structure, + * and also a type of containment (it may be contained + * as pointer or using inline inclusion). + */ + if(elm->flags & ATF_POINTER) { + /* Member is a pointer to another structure */ + memb_ptr2 = (void **)((char *)st + elm->memb_offset); + } else { + /* + * A pointer to a pointer + * holding the start of the structure + */ + memb_ptr = (char *)st + elm->memb_offset; + memb_ptr2 = &memb_ptr; + } + + /* Set presence to be able to free it properly at any time */ + (void)CHOICE_variant_set_presence(td, st, ctx->step + 1); + + if(specs->ext_start >= 0 && specs->ext_start <= ctx->step) { + ssize_t got = + oer_open_type_get(opt_codec_ctx, elm->type, + elm->encoding_constraints.oer_constraints, + memb_ptr2, ptr, size); + if(got < 0) ASN__DECODE_FAILED; + if(got == 0) ASN__DECODE_STARVED; + rval.code = RC_OK; + rval.consumed = got; + } else { + rval = elm->type->op->oer_decoder( + opt_codec_ctx, elm->type, + elm->encoding_constraints.oer_constraints, memb_ptr2, ptr, + size); + } + rval.consumed += consumed_myself; + switch(rval.code) { + case RC_OK: + NEXT_PHASE(ctx); + case RC_WMORE: + break; + case RC_FAIL: + SET_PHASE(ctx, 3); /* => 3 */ + } + return rval; + } + case 2: + /* Already decoded everything */ + RETURN(RC_OK); + case 3: + /* Failed to decode, after all */ + RETURN(RC_FAIL); + } + + RETURN(RC_FAIL); +} + +/* + * X.696 (08/2015) #8.7 Encoding of tags + */ +static ssize_t +oer_put_tag(ber_tlv_tag_t tag, asn_app_consume_bytes_f *cb, void *app_key) { + uint8_t tclass = BER_TAG_CLASS(tag); + ber_tlv_tag_t tval = BER_TAG_VALUE(tag); + + if(tval < 0x3F) { + uint8_t b = (uint8_t)((tclass << 6) | tval); + if(cb(&b, 1, app_key) < 0) { + return -1; + } + return 1; + } else { + uint8_t buf[1 + 2 * sizeof(tval)]; + uint8_t *b = &buf[sizeof(buf)-1]; /* Last addressable */ + size_t encoded; + for(; ; tval >>= 7) { + if(tval >> 7) { + *b-- = 0x80 | (tval & 0x7f); + } else { + *b-- = tval & 0x7f; + break; + } + } + *b = (uint8_t)((tclass << 6) | 0x3F); + encoded = sizeof(buf) - (b - buf); + if(cb(b, encoded, app_key) < 0) { + return -1; + } + return encoded; + } + +} + +/* + * Encode as Canonical OER. + */ +asn_enc_rval_t +CHOICE_encode_oer(const asn_TYPE_descriptor_t *td, + const asn_oer_constraints_t *constraints, const void *sptr, + asn_app_consume_bytes_f *cb, void *app_key) { + const asn_CHOICE_specifics_t *specs = + (const asn_CHOICE_specifics_t *)td->specifics; + asn_TYPE_member_t *elm; /* CHOICE element */ + unsigned present; + const void *memb_ptr; + ber_tlv_tag_t tag; + ssize_t tag_len; + asn_enc_rval_t er = {0, 0, 0}; + + (void)constraints; + + if(!sptr) ASN__ENCODE_FAILED; + + ASN_DEBUG("OER %s encoding as CHOICE", td->name); + + present = CHOICE_variant_get_presence(td, sptr); + if(present == 0 || present > td->elements_count) { + ASN_DEBUG("CHOICE %s member is not selected", td->name); + ASN__ENCODE_FAILED; + } + + elm = &td->elements[present-1]; + if(elm->flags & ATF_POINTER) { + memb_ptr = + *(const void *const *)((const char *)sptr + elm->memb_offset); + if(memb_ptr == 0) { + /* Mandatory element absent */ + ASN__ENCODE_FAILED; + } + } else { + memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); + } + + tag = asn_TYPE_outmost_tag(elm->type, memb_ptr, elm->tag_mode, elm->tag); + if(tag == 0) { + ASN__ENCODE_FAILED; + } + + tag_len = oer_put_tag(tag, cb, app_key); + if(tag_len < 0) { + ASN__ENCODE_FAILED; + } + + if(specs->ext_start >= 0 && (unsigned)specs->ext_start <= (present-1)) { + ssize_t encoded = oer_open_type_put(elm->type, + elm->encoding_constraints.oer_constraints, + memb_ptr, cb, app_key); + if(encoded < 0) ASN__ENCODE_FAILED; + er.encoded = tag_len + encoded; + } else { + er = elm->type->op->oer_encoder( + elm->type, elm->encoding_constraints.oer_constraints, memb_ptr, cb, + app_key); + if(er.encoded >= 0) er.encoded += tag_len; + } + + return er; +} + +#endif /* ASN_DISABLE_OER_SUPPORT */ diff --git a/Vendor/asn1/include/constr_SEQUENCE.c b/Vendor/asn1/include/constr_SEQUENCE.c new file mode 100644 index 0000000..2fbf97b --- /dev/null +++ b/Vendor/asn1/include/constr_SEQUENCE.c @@ -0,0 +1,1626 @@ +/* + * Copyright (c) 2003-2017 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include +#include + +/* + * Number of bytes left for this structure. + * (ctx->left) indicates the number of bytes _transferred_ for the structure. + * (size) contains the number of bytes in the buffer passed. + */ +#define LEFT ((size<(size_t)ctx->left)?size:(size_t)ctx->left) + +/* + * If the subprocessor function returns with an indication that it wants + * more data, it may well be a fatal decoding problem, because the + * size is constrained by the 's L, even if the buffer size allows + * reading more data. + * For example, consider the buffer containing the following TLVs: + * ... + * The TLV length clearly indicates that one byte is expected in V, but + * if the V processor returns with "want more data" even if the buffer + * contains way more data than the V processor have seen. + */ +#define SIZE_VIOLATION (ctx->left >= 0 && (size_t)ctx->left <= size) + +/* + * This macro "eats" the part of the buffer which is definitely "consumed", + * i.e. was correctly converted into local representation or rightfully skipped. + */ +#undef ADVANCE +#define ADVANCE(num_bytes) do { \ + size_t num = num_bytes; \ + ptr = ((const char *)ptr) + num; \ + size -= num; \ + if(ctx->left >= 0) \ + ctx->left -= num; \ + consumed_myself += num; \ + } while(0) + +/* + * Switch to the next phase of parsing. + */ +#undef NEXT_PHASE +#undef PHASE_OUT +#define NEXT_PHASE(ctx) do { \ + ctx->phase++; \ + ctx->step = 0; \ + } while(0) +#define PHASE_OUT(ctx) do { ctx->phase = 10; } while(0) + +/* + * Return a standardized complex structure. + */ +#undef RETURN +#define RETURN(_code) do { \ + rval.code = _code; \ + rval.consumed = consumed_myself;\ + return rval; \ + } while(0) + +/* + * Check whether we are inside the extensions group. + */ +#define IN_EXTENSION_GROUP(specs, memb_idx) \ + ((specs)->first_extension >= 0 \ + && (unsigned)(specs)->first_extension <= (memb_idx)) + +/* + * Tags are canonically sorted in the tag2element map. + */ +static int +_t2e_cmp(const void *ap, const void *bp) { + const asn_TYPE_tag2member_t *a = (const asn_TYPE_tag2member_t *)ap; + const asn_TYPE_tag2member_t *b = (const asn_TYPE_tag2member_t *)bp; + + int a_class = BER_TAG_CLASS(a->el_tag); + int b_class = BER_TAG_CLASS(b->el_tag); + + if(a_class == b_class) { + ber_tlv_tag_t a_value = BER_TAG_VALUE(a->el_tag); + ber_tlv_tag_t b_value = BER_TAG_VALUE(b->el_tag); + + if(a_value == b_value) { + if(a->el_no > b->el_no) + return 1; + /* + * Important: we do not check + * for a->el_no <= b->el_no! + */ + return 0; + } else if(a_value < b_value) + return -1; + else + return 1; + } else if(a_class < b_class) { + return -1; + } else { + return 1; + } +} + + +/* + * The decoder of the SEQUENCE type. + */ +asn_dec_rval_t +SEQUENCE_decode_ber(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, void **struct_ptr, + const void *ptr, size_t size, int tag_mode) { + /* + * Bring closer parts of structure description. + */ + const asn_SEQUENCE_specifics_t *specs = (const asn_SEQUENCE_specifics_t *)td->specifics; + const asn_TYPE_member_t *elements = td->elements; + + /* + * Parts of the structure being constructed. + */ + void *st = *struct_ptr; /* Target structure. */ + asn_struct_ctx_t *ctx; /* Decoder context */ + + ber_tlv_tag_t tlv_tag; /* T from TLV */ + asn_dec_rval_t rval; /* Return code from subparsers */ + + ssize_t consumed_myself = 0; /* Consumed bytes from ptr */ + size_t edx; /* SEQUENCE element's index */ + + ASN_DEBUG("Decoding %s as SEQUENCE", td->name); + + /* + * Create the target structure if it is not present already. + */ + if(st == 0) { + st = *struct_ptr = CALLOC(1, specs->struct_size); + if(st == 0) { + RETURN(RC_FAIL); + } + } + + /* + * Restore parsing context. + */ + ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); + + /* + * Start to parse where left previously + */ + switch(ctx->phase) { + case 0: + /* + * PHASE 0. + * Check that the set of tags associated with given structure + * perfectly fits our expectations. + */ + + rval = ber_check_tags(opt_codec_ctx, td, ctx, ptr, size, + tag_mode, 1, &ctx->left, 0); + if(rval.code != RC_OK) { + ASN_DEBUG("%s tagging check failed: %d", + td->name, rval.code); + return rval; + } + + if(ctx->left >= 0) + ctx->left += rval.consumed; /* ?Substracted below! */ + ADVANCE(rval.consumed); + + NEXT_PHASE(ctx); + + ASN_DEBUG("Structure consumes %ld bytes, buffer %ld", + (long)ctx->left, (long)size); + + /* Fall through */ + case 1: + /* + * PHASE 1. + * From the place where we've left it previously, + * try to decode the next member from the list of + * this structure's elements. + * (ctx->step) stores the member being processed + * between invocations and the microphase {0,1} of parsing + * that member: + * step = ( * 2 + ). + */ + for(edx = ((size_t)ctx->step >> 1); edx < td->elements_count; + edx++, ctx->step = (ctx->step & ~1) + 2) { + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + ssize_t tag_len; /* Length of TLV's T */ + size_t opt_edx_end; /* Next non-optional element */ + size_t n; + int use_bsearch; + + if(ctx->step & 1) + goto microphase2; + + /* + * MICROPHASE 1: Synchronize decoding. + */ + ASN_DEBUG("In %s SEQUENCE left %d, edx=%" ASN_PRI_SIZE " flags=%d" + " opt=%d ec=%d", + td->name, (int)ctx->left, edx, + elements[edx].flags, elements[edx].optional, + td->elements_count); + + if(ctx->left == 0 /* No more stuff is expected */ + && ( + /* Explicit OPTIONAL specification reaches the end */ + (edx + elements[edx].optional == td->elements_count) || + /* All extensions are optional */ + IN_EXTENSION_GROUP(specs, edx))) { + ASN_DEBUG("End of SEQUENCE %s", td->name); + /* + * Found the legitimate end of the structure. + */ + PHASE_OUT(ctx); + RETURN(RC_OK); + } + + /* + * Fetch the T from TLV. + */ + tag_len = ber_fetch_tag(ptr, LEFT, &tlv_tag); + ASN_DEBUG("Current tag in %s SEQUENCE for element %" ASN_PRI_SIZE " " + "(%s) is %s encoded in %d bytes, of frame %ld", + td->name, edx, elements[edx].name, + ber_tlv_tag_string(tlv_tag), (int)tag_len, (long)LEFT); + switch(tag_len) { + case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); + /* Fall through */ + case -1: RETURN(RC_FAIL); + } + + if(ctx->left < 0 && ((const uint8_t *)ptr)[0] == 0) { + if(LEFT < 2) { + if(SIZE_VIOLATION) { + RETURN(RC_FAIL); + } else { + RETURN(RC_WMORE); + } + } else if(((const uint8_t *)ptr)[1] == 0) { + ASN_DEBUG("edx = %" ASN_PRI_SIZE ", opt = %d, ec=%d", edx, + elements[edx].optional, td->elements_count); + if((edx + elements[edx].optional == td->elements_count) + || IN_EXTENSION_GROUP(specs, edx)) { + /* + * Yeah, baby! Found the terminator + * of the indefinite length structure. + */ + /* + * Proceed to the canonical + * finalization function. + * No advancing is necessary. + */ + goto phase3; + } + } + } + + /* + * Find the next available type with this tag. + */ + use_bsearch = 0; + opt_edx_end = edx + elements[edx].optional + 1; + if(opt_edx_end > td->elements_count) + opt_edx_end = td->elements_count; /* Cap */ + else if(opt_edx_end - edx > 8) { + /* Limit the scope of linear search... */ + opt_edx_end = edx + 8; + use_bsearch = 1; + /* ... and resort to bsearch() */ + } + for(n = edx; n < opt_edx_end; n++) { + if(BER_TAGS_EQUAL(tlv_tag, elements[n].tag)) { + /* + * Found element corresponding to the tag + * being looked at. + * Reposition over the right element. + */ + edx = n; + ctx->step = 1 + 2 * edx; /* Remember! */ + goto microphase2; + } else if(elements[n].flags & ATF_ANY_TYPE) { + /* + * This is the ANY type, which may bear + * any flag whatsoever. + */ + edx = n; + ctx->step = 1 + 2 * edx; /* Remember! */ + goto microphase2; + } else if(elements[n].tag == (ber_tlv_tag_t)-1) { + use_bsearch = 1; + break; + } + } + if(use_bsearch) { + /* + * Resort to a binary search over + * sorted array of tags. + */ + const asn_TYPE_tag2member_t *t2m; + asn_TYPE_tag2member_t key = {0, 0, 0, 0}; + key.el_tag = tlv_tag; + key.el_no = edx; + t2m = (const asn_TYPE_tag2member_t *)bsearch(&key, + specs->tag2el, specs->tag2el_count, + sizeof(specs->tag2el[0]), _t2e_cmp); + if(t2m) { + const asn_TYPE_tag2member_t *best = 0; + const asn_TYPE_tag2member_t *t2m_f, *t2m_l; + size_t edx_max = edx + elements[edx].optional; + /* + * Rewind to the first element with that tag, + * `cause bsearch() does not guarantee order. + */ + t2m_f = t2m + t2m->toff_first; + t2m_l = t2m + t2m->toff_last; + for(t2m = t2m_f; t2m <= t2m_l; t2m++) { + if(t2m->el_no > edx_max) break; + if(t2m->el_no < edx) continue; + best = t2m; + } + if(best) { + edx = best->el_no; + ctx->step = 1 + 2 * edx; + goto microphase2; + } + } + n = opt_edx_end; + } + if(n == opt_edx_end) { + /* + * If tag is unknown, it may be either + * an unknown (thus, incorrect) tag, + * or an extension (...), + * or an end of the indefinite-length structure. + */ + if(!IN_EXTENSION_GROUP(specs, + edx + elements[edx].optional)) { + ASN_DEBUG("Unexpected tag %s (at %" ASN_PRI_SIZE ")", + ber_tlv_tag_string(tlv_tag), edx); + ASN_DEBUG("Expected tag %s (%s)%s", + ber_tlv_tag_string(elements[edx].tag), + elements[edx].name, + elements[edx].optional + ?" or alternatives":""); + RETURN(RC_FAIL); + } else { + /* Skip this tag */ + ssize_t skip; + edx += elements[edx].optional; + + ASN_DEBUG("Skipping unexpected %s (at %" ASN_PRI_SIZE ")", + ber_tlv_tag_string(tlv_tag), edx); + skip = ber_skip_length(opt_codec_ctx, + BER_TLV_CONSTRUCTED(ptr), + (const char *)ptr + tag_len, + LEFT - tag_len); + ASN_DEBUG("Skip length %d in %s", + (int)skip, td->name); + switch(skip) { + case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); + /* Fall through */ + case -1: RETURN(RC_FAIL); + } + + ADVANCE(skip + tag_len); + ctx->step -= 2; + edx--; + continue; /* Try again with the next tag */ + } + } + + /* + * MICROPHASE 2: Invoke the member-specific decoder. + */ + ctx->step |= 1; /* Confirm entering next microphase */ + microphase2: + ASN_DEBUG("Inside SEQUENCE %s MF2", td->name); + + /* + * Compute the position of the member inside a structure, + * and also a type of containment (it may be contained + * as pointer or using inline inclusion). + */ + if(elements[edx].flags & ATF_POINTER) { + /* Member is a pointer to another structure */ + memb_ptr2 = (void **)((char *)st + elements[edx].memb_offset); + } else { + /* + * A pointer to a pointer + * holding the start of the structure + */ + memb_ptr = (char *)st + elements[edx].memb_offset; + memb_ptr2 = &memb_ptr; + } + /* + * Invoke the member fetch routine according to member's type + */ + if(elements[edx].flags & ATF_OPEN_TYPE) { + rval = OPEN_TYPE_ber_get(opt_codec_ctx, td, st, &elements[edx], ptr, LEFT); + } else { + rval = elements[edx].type->op->ber_decoder(opt_codec_ctx, + elements[edx].type, + memb_ptr2, ptr, LEFT, + elements[edx].tag_mode); + } + ASN_DEBUG("In %s SEQUENCE decoded %" ASN_PRI_SIZE " %s of %d " + "in %d bytes rval.code %d, size=%d", + td->name, edx, elements[edx].type->name, + (int)LEFT, (int)rval.consumed, rval.code, (int)size); + switch(rval.code) { + case RC_OK: + break; + case RC_WMORE: /* More data expected */ + if(!SIZE_VIOLATION) { + ADVANCE(rval.consumed); + RETURN(RC_WMORE); + } + ASN_DEBUG("Size violation (c->l=%ld <= s=%ld)", + (long)ctx->left, (long)size); + /* Fall through */ + case RC_FAIL: /* Fatal error */ + RETURN(RC_FAIL); + } /* switch(rval) */ + + ADVANCE(rval.consumed); + } /* for(all structure members) */ + + phase3: + ctx->phase = 3; + /* Fall through */ + case 3: /* 00 and other tags expected */ + case 4: /* only 00's expected */ + + ASN_DEBUG("SEQUENCE %s Leftover: %ld, size = %ld", + td->name, (long)ctx->left, (long)size); + + /* + * Skip everything until the end of the SEQUENCE. + */ + while(ctx->left) { + ssize_t tl, ll; + + tl = ber_fetch_tag(ptr, LEFT, &tlv_tag); + switch(tl) { + case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); + /* Fall through */ + case -1: RETURN(RC_FAIL); + } + + /* + * If expected <0><0>... + */ + if(ctx->left < 0 + && ((const uint8_t *)ptr)[0] == 0) { + if(LEFT < 2) { + if(SIZE_VIOLATION) + RETURN(RC_FAIL); + else + RETURN(RC_WMORE); + } else if(((const uint8_t *)ptr)[1] == 0) { + /* + * Correctly finished with <0><0>. + */ + ADVANCE(2); + ctx->left++; + ctx->phase = 4; + continue; + } + } + + if(!IN_EXTENSION_GROUP(specs, td->elements_count) + || ctx->phase == 4) { + ASN_DEBUG("Unexpected continuation " + "of a non-extensible type " + "%s (SEQUENCE): %s", + td->name, + ber_tlv_tag_string(tlv_tag)); + RETURN(RC_FAIL); + } + + ll = ber_skip_length(opt_codec_ctx, + BER_TLV_CONSTRUCTED(ptr), + (const char *)ptr + tl, LEFT - tl); + switch(ll) { + case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); + /* Fall through */ + case -1: RETURN(RC_FAIL); + } + + ADVANCE(tl + ll); + } + + PHASE_OUT(ctx); + } + + RETURN(RC_OK); +} + + +/* + * The DER encoder of the SEQUENCE type. + */ +asn_enc_rval_t +SEQUENCE_encode_der(const asn_TYPE_descriptor_t *td, const void *sptr, + int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + size_t computed_size = 0; + asn_enc_rval_t erval; + ssize_t ret; + size_t edx; + + ASN_DEBUG("%s %s as SEQUENCE", + cb?"Encoding":"Estimating", td->name); + + /* + * Gather the length of the underlying members sequence. + */ + for(edx = 0; edx < td->elements_count; edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + + const void *memb_ptr; /* Pointer to the member */ + const void *const *memb_ptr2; /* Pointer to that pointer */ + + if(elm->flags & ATF_POINTER) { + memb_ptr2 = + (const void *const *)((const char *)sptr + elm->memb_offset); + if(!*memb_ptr2) { + ASN_DEBUG("Element %s %" ASN_PRI_SIZE " not present", + elm->name, edx); + if(elm->optional) + continue; + /* Mandatory element is missing */ + ASN__ENCODE_FAILED; + } + } else { + memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); + memb_ptr2 = &memb_ptr; + } + + /* Eliminate default values */ + if(elm->default_value_cmp && elm->default_value_cmp(*memb_ptr2) == 0) + continue; + + erval = elm->type->op->der_encoder(elm->type, *memb_ptr2, + elm->tag_mode, elm->tag, + 0, 0); + if(erval.encoded == -1) + return erval; + computed_size += erval.encoded; + ASN_DEBUG("Member %" ASN_PRI_SIZE " %s estimated %ld bytes", + edx, elm->name, (long)erval.encoded); + } + + /* + * Encode the TLV for the sequence itself. + */ + ret = der_write_tags(td, computed_size, tag_mode, 1, tag, cb, app_key); + ASN_DEBUG("Wrote tags: %ld (+%ld)", (long)ret, (long)computed_size); + if(ret == -1) + ASN__ENCODE_FAILED; + erval.encoded = computed_size + ret; + + if(!cb) ASN__ENCODED_OK(erval); + + /* + * Encode all members. + */ + for(edx = 0; edx < td->elements_count; edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + asn_enc_rval_t tmperval; + const void *memb_ptr; /* Pointer to the member */ + const void *const *memb_ptr2; /* Pointer to that pointer */ + + if(elm->flags & ATF_POINTER) { + memb_ptr2 = + (const void *const *)((const char *)sptr + elm->memb_offset); + if(!*memb_ptr2) continue; + } else { + memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); + memb_ptr2 = &memb_ptr; + } + + /* Eliminate default values */ + if(elm->default_value_cmp && elm->default_value_cmp(*memb_ptr2) == 0) + continue; + + tmperval = elm->type->op->der_encoder(elm->type, *memb_ptr2, + elm->tag_mode, elm->tag, cb, app_key); + if(tmperval.encoded == -1) + return tmperval; + computed_size -= tmperval.encoded; + ASN_DEBUG("Member %" ASN_PRI_SIZE " %s of SEQUENCE %s encoded in %ld bytes", + edx, elm->name, td->name, (long)tmperval.encoded); + } + + if(computed_size != 0) + /* + * Encoded size is not equal to the computed size. + */ + ASN__ENCODE_FAILED; + + ASN__ENCODED_OK(erval); +} + + +#undef XER_ADVANCE +#define XER_ADVANCE(num_bytes) \ + do { \ + size_t num = (num_bytes); \ + ptr = ((const char *)ptr) + num; \ + size -= num; \ + consumed_myself += num; \ + } while(0) + +/* + * Decode the XER (XML) data. + */ +asn_dec_rval_t +SEQUENCE_decode_xer(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, void **struct_ptr, + const char *opt_mname, const void *ptr, size_t size) { + /* + * Bring closer parts of structure description. + */ + const asn_SEQUENCE_specifics_t *specs + = (const asn_SEQUENCE_specifics_t *)td->specifics; + asn_TYPE_member_t *elements = td->elements; + const char *xml_tag = opt_mname ? opt_mname : td->xml_tag; + + /* + * ... and parts of the structure being constructed. + */ + void *st = *struct_ptr; /* Target structure. */ + asn_struct_ctx_t *ctx; /* Decoder context */ + + asn_dec_rval_t rval; /* Return value from a decoder */ + ssize_t consumed_myself = 0; /* Consumed bytes from ptr */ + size_t edx; /* Element index */ + + /* + * Create the target structure if it is not present already. + */ + if(st == 0) { + st = *struct_ptr = CALLOC(1, specs->struct_size); + if(st == 0) RETURN(RC_FAIL); + } + + /* + * Restore parsing context. + */ + ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); + + + /* + * Phases of XER/XML processing: + * Phase 0: Check that the opening tag matches our expectations. + * Phase 1: Processing body and reacting on closing tag. + * Phase 2: Processing inner type. + * Phase 3: Skipping unknown extensions. + * Phase 4: PHASED OUT + */ + for(edx = ctx->step; ctx->phase <= 3;) { + pxer_chunk_type_e ch_type; /* XER chunk type */ + ssize_t ch_size; /* Chunk size */ + xer_check_tag_e tcv; /* Tag check value */ + asn_TYPE_member_t *elm; + + /* + * Go inside the inner member of a sequence. + */ + if(ctx->phase == 2) { + asn_dec_rval_t tmprval; + void *memb_ptr_dontuse; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + + elm = &td->elements[edx]; + + if(elm->flags & ATF_POINTER) { + /* Member is a pointer to another structure */ + memb_ptr2 = (void **)((char *)st + elm->memb_offset); + } else { + memb_ptr_dontuse = (char *)st + elm->memb_offset; + memb_ptr2 = &memb_ptr_dontuse; /* Only use of memb_ptr_dontuse */ + } + + if(elm->flags & ATF_OPEN_TYPE) { + tmprval = OPEN_TYPE_xer_get(opt_codec_ctx, td, st, elm, ptr, size); + } else { + /* Invoke the inner type decoder, m.b. multiple times */ + tmprval = elm->type->op->xer_decoder(opt_codec_ctx, + elm->type, memb_ptr2, elm->name, + ptr, size); + } + XER_ADVANCE(tmprval.consumed); + if(tmprval.code != RC_OK) + RETURN(tmprval.code); + ctx->phase = 1; /* Back to body processing */ + ctx->step = ++edx; + ASN_DEBUG("XER/SEQUENCE phase => %d, step => %d", + ctx->phase, ctx->step); + /* Fall through */ + } + + /* + * Get the next part of the XML stream. + */ + ch_size = xer_next_token(&ctx->context, ptr, size, + &ch_type); + if(ch_size == -1) { + RETURN(RC_FAIL); + } else { + switch(ch_type) { + case PXER_WMORE: + RETURN(RC_WMORE); + case PXER_COMMENT: /* Got XML comment */ + case PXER_TEXT: /* Ignore free-standing text */ + XER_ADVANCE(ch_size); /* Skip silently */ + continue; + case PXER_TAG: + break; /* Check the rest down there */ + } + } + + tcv = xer_check_tag(ptr, ch_size, xml_tag); + ASN_DEBUG("XER/SEQUENCE: tcv = %d, ph=%d [%s]", + tcv, ctx->phase, xml_tag); + + /* Skip the extensions section */ + if(ctx->phase == 3) { + switch(xer_skip_unknown(tcv, &ctx->left)) { + case -1: + ctx->phase = 4; + RETURN(RC_FAIL); + case 0: + XER_ADVANCE(ch_size); + continue; + case 1: + XER_ADVANCE(ch_size); + ctx->phase = 1; + continue; + case 2: + ctx->phase = 1; + break; + } + } + + switch(tcv) { + case XCT_CLOSING: + if(ctx->phase == 0) break; + ctx->phase = 0; + /* Fall through */ + case XCT_BOTH: + if(ctx->phase == 0) { + if(edx >= td->elements_count || + /* Explicit OPTIONAL specs reaches the end */ + (edx + elements[edx].optional == td->elements_count) || + /* All extensions are optional */ + IN_EXTENSION_GROUP(specs, edx)) { + XER_ADVANCE(ch_size); + ctx->phase = 4; /* Phase out */ + RETURN(RC_OK); + } else { + ASN_DEBUG("Premature end of XER SEQUENCE"); + RETURN(RC_FAIL); + } + } + /* Fall through */ + case XCT_OPENING: + if(ctx->phase == 0) { + XER_ADVANCE(ch_size); + ctx->phase = 1; /* Processing body phase */ + continue; + } + /* Fall through */ + case XCT_UNKNOWN_OP: + case XCT_UNKNOWN_BO: + + ASN_DEBUG("XER/SEQUENCE: tcv=%d, ph=%d, edx=%" ASN_PRI_SIZE "", + tcv, ctx->phase, edx); + if(ctx->phase != 1) { + break; /* Really unexpected */ + } + + if(edx < td->elements_count) { + /* + * Search which member corresponds to this tag. + */ + size_t n; + size_t edx_end = edx + elements[edx].optional + 1; + if(edx_end > td->elements_count) + edx_end = td->elements_count; + for(n = edx; n < edx_end; n++) { + elm = &td->elements[n]; + tcv = xer_check_tag(ptr, ch_size, elm->name); + switch(tcv) { + case XCT_BOTH: + case XCT_OPENING: + /* + * Process this member. + */ + ctx->step = edx = n; + ctx->phase = 2; + break; + case XCT_UNKNOWN_OP: + case XCT_UNKNOWN_BO: + continue; + default: + n = edx_end; + break; /* Phase out */ + } + break; + } + if(n != edx_end) + continue; + } else { + ASN_DEBUG("Out of defined members: %" ASN_PRI_SIZE "/%u", + edx, td->elements_count); + } + + /* It is expected extension */ + if(IN_EXTENSION_GROUP(specs, + edx + (edx < td->elements_count + ? elements[edx].optional : 0))) { + ASN_DEBUG("Got anticipated extension at %" ASN_PRI_SIZE "", + edx); + /* + * Check for (XCT_BOTH or XCT_UNKNOWN_BO) + * By using a mask. Only record a pure + * tags. + */ + if(tcv & XCT_CLOSING) { + /* Found without body */ + } else { + ctx->left = 1; + ctx->phase = 3; /* Skip ...'s */ + } + XER_ADVANCE(ch_size); + continue; + } + + /* Fall through */ + default: + break; + } + + ASN_DEBUG("Unexpected XML tag in SEQUENCE [%c%c%c%c%c%c]", + size>0?((const char *)ptr)[0]:'.', + size>1?((const char *)ptr)[1]:'.', + size>2?((const char *)ptr)[2]:'.', + size>3?((const char *)ptr)[3]:'.', + size>4?((const char *)ptr)[4]:'.', + size>5?((const char *)ptr)[5]:'.'); + break; + } + + ctx->phase = 4; /* "Phase out" on hard failure */ + RETURN(RC_FAIL); +} + +asn_enc_rval_t +SEQUENCE_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_enc_rval_t er; + int xcan = (flags & XER_F_CANONICAL); + asn_TYPE_descriptor_t *tmp_def_val_td = 0; + void *tmp_def_val = 0; + size_t edx; + + if(!sptr) ASN__ENCODE_FAILED; + + er.encoded = 0; + + for(edx = 0; edx < td->elements_count; edx++) { + asn_enc_rval_t tmper; + asn_TYPE_member_t *elm = &td->elements[edx]; + const void *memb_ptr; + const char *mname = elm->name; + unsigned int mlen = strlen(mname); + + if(elm->flags & ATF_POINTER) { + memb_ptr = + *(const void *const *)((const char *)sptr + elm->memb_offset); + if(!memb_ptr) { + assert(tmp_def_val == 0); + if(elm->default_value_set) { + if(elm->default_value_set(&tmp_def_val)) { + ASN__ENCODE_FAILED; + } else { + memb_ptr = tmp_def_val; + tmp_def_val_td = elm->type; + } + } else if(elm->optional) { + continue; + } else { + /* Mandatory element is missing */ + ASN__ENCODE_FAILED; + } + } + } else { + memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); + } + + if(!xcan) ASN__TEXT_INDENT(1, ilevel); + ASN__CALLBACK3("<", 1, mname, mlen, ">", 1); + + /* Print the member itself */ + tmper = elm->type->op->xer_encoder(elm->type, memb_ptr, ilevel + 1, + flags, cb, app_key); + if(tmp_def_val) { + ASN_STRUCT_FREE(*tmp_def_val_td, tmp_def_val); + tmp_def_val = 0; + } + if(tmper.encoded == -1) return tmper; + er.encoded += tmper.encoded; + + ASN__CALLBACK3("", 1); + } + + if(!xcan) ASN__TEXT_INDENT(1, ilevel - 1); + + ASN__ENCODED_OK(er); +cb_failed: + if(tmp_def_val) ASN_STRUCT_FREE(*tmp_def_val_td, tmp_def_val); + ASN__ENCODE_FAILED; +} + +int +SEQUENCE_print(const asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, + asn_app_consume_bytes_f *cb, void *app_key) { + size_t edx; + int ret; + + if(!sptr) return (cb("", 8, app_key) < 0) ? -1 : 0; + + /* Dump preamble */ + if(cb(td->name, strlen(td->name), app_key) < 0 + || cb(" ::= {", 6, app_key) < 0) + return -1; + + for(edx = 0; edx < td->elements_count; edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + const void *memb_ptr; + + if(elm->flags & ATF_POINTER) { + memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset); + if(!memb_ptr) { + if(elm->optional) continue; + /* Print line */ + /* Fall through */ + } + } else { + memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); + } + + /* Indentation */ + _i_INDENT(1); + + /* Print the member's name and stuff */ + if(cb(elm->name, strlen(elm->name), app_key) < 0 + || cb(": ", 2, app_key) < 0) + return -1; + + /* Print the member itself */ + ret = elm->type->op->print_struct(elm->type, memb_ptr, ilevel + 1, + cb, app_key); + if(ret) return ret; + } + + ilevel--; + _i_INDENT(1); + + return (cb("}", 1, app_key) < 0) ? -1 : 0; +} + +void +SEQUENCE_free(const asn_TYPE_descriptor_t *td, void *sptr, + enum asn_struct_free_method method) { + size_t edx; + const asn_SEQUENCE_specifics_t *specs = + (const asn_SEQUENCE_specifics_t *)td->specifics; + asn_struct_ctx_t *ctx; /* Decoder context */ + + if(!td || !sptr) + return; + + ASN_DEBUG("Freeing %s as SEQUENCE", td->name); + + for(edx = 0; edx < td->elements_count; edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + void *memb_ptr; + if(elm->flags & ATF_POINTER) { + memb_ptr = *(void **)((char *)sptr + elm->memb_offset); + if(memb_ptr) + ASN_STRUCT_FREE(*elm->type, memb_ptr); + } else { + memb_ptr = (void *)((char *)sptr + elm->memb_offset); + ASN_STRUCT_FREE_CONTENTS_ONLY(*elm->type, memb_ptr); + } + } + + /* Clean parsing context */ + ctx = (asn_struct_ctx_t *)((char *)sptr + specs->ctx_offset); + FREEMEM(ctx->ptr); + + switch(method) { + case ASFM_FREE_EVERYTHING: + FREEMEM(sptr); + break; + case ASFM_FREE_UNDERLYING: + break; + case ASFM_FREE_UNDERLYING_AND_RESET: + memset( + sptr, 0, + ((const asn_SEQUENCE_specifics_t *)(td->specifics))->struct_size); + break; + } +} + +int +SEQUENCE_constraint(const asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + size_t edx; + + if(!sptr) { + ASN__CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + /* + * Iterate over structure members and check their validity. + */ + for(edx = 0; edx < td->elements_count; edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + const void *memb_ptr; + + if(elm->flags & ATF_POINTER) { + memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset); + if(!memb_ptr) { + if(elm->optional) + continue; + ASN__CTFAIL(app_key, td, sptr, + "%s: mandatory element %s absent (%s:%d)", + td->name, elm->name, __FILE__, __LINE__); + return -1; + } + } else { + memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); + } + + if(elm->encoding_constraints.general_constraints) { + int ret = elm->encoding_constraints.general_constraints(elm->type, memb_ptr, + ctfailcb, app_key); + if(ret) return ret; + } else { + return elm->type->encoding_constraints.general_constraints(elm->type, + memb_ptr, ctfailcb, app_key); + } + } + + return 0; +} + +#ifndef ASN_DISABLE_PER_SUPPORT + +asn_dec_rval_t +SEQUENCE_decode_uper(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, + const asn_per_constraints_t *constraints, void **sptr, + asn_per_data_t *pd) { + const asn_SEQUENCE_specifics_t *specs = (const asn_SEQUENCE_specifics_t *)td->specifics; + void *st = *sptr; /* Target structure. */ + int extpresent; /* Extension additions are present */ + uint8_t *opres; /* Presence of optional root members */ + asn_per_data_t opmd; + asn_dec_rval_t rv; + size_t edx; + + (void)constraints; + + if(ASN__STACK_OVERFLOW_CHECK(opt_codec_ctx)) + ASN__DECODE_FAILED; + + if(!st) { + st = *sptr = CALLOC(1, specs->struct_size); + if(!st) ASN__DECODE_FAILED; + } + + ASN_DEBUG("Decoding %s as SEQUENCE (UPER)", td->name); + + /* Handle extensions */ + if(specs->first_extension < 0) { + extpresent = 0; + } else { + extpresent = per_get_few_bits(pd, 1); + if(extpresent < 0) ASN__DECODE_STARVED; + } + + /* Prepare a place and read-in the presence bitmap */ + memset(&opmd, 0, sizeof(opmd)); + if(specs->roms_count) { + opres = (uint8_t *)MALLOC(((specs->roms_count + 7) >> 3) + 1); + if(!opres) ASN__DECODE_FAILED; + /* Get the presence map */ + if(per_get_many_bits(pd, opres, 0, specs->roms_count)) { + FREEMEM(opres); + ASN__DECODE_STARVED; + } + opmd.buffer = opres; + opmd.nbits = specs->roms_count; + ASN_DEBUG("Read in presence bitmap for %s of %d bits (%x..)", + td->name, specs->roms_count, *opres); + } else { + opres = 0; + } + + /* + * Get the sequence ROOT elements. + */ + for(edx = 0; + edx < (specs->first_extension < 0 ? td->elements_count + : (size_t)specs->first_extension); + edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + + assert(!IN_EXTENSION_GROUP(specs, edx)); + + /* Fetch the pointer to this member */ + if(elm->flags & ATF_POINTER) { + memb_ptr2 = (void **)((char *)st + elm->memb_offset); + } else { + memb_ptr = (char *)st + elm->memb_offset; + memb_ptr2 = &memb_ptr; + } + + /* Deal with optionality */ + if(elm->optional) { + int present = per_get_few_bits(&opmd, 1); + ASN_DEBUG("Member %s->%s is optional, p=%d (%d->%d)", + td->name, elm->name, present, + (int)opmd.nboff, (int)opmd.nbits); + if(present == 0) { + /* This element is not present */ + if(elm->default_value_set) { + /* Fill-in DEFAULT */ + if(elm->default_value_set(memb_ptr2)) { + FREEMEM(opres); + ASN__DECODE_FAILED; + } + ASN_DEBUG("Filled-in default"); + } + /* The member is just not present */ + continue; + } + /* Fall through */ + } + + /* Fetch the member from the stream */ + ASN_DEBUG("Decoding member \"%s\" in %s", elm->name, td->name); + + if(elm->flags & ATF_OPEN_TYPE) { + rv = OPEN_TYPE_uper_get(opt_codec_ctx, td, st, elm, pd); + } else { + rv = elm->type->op->uper_decoder(opt_codec_ctx, elm->type, + elm->encoding_constraints.per_constraints, memb_ptr2, pd); + } + if(rv.code != RC_OK) { + ASN_DEBUG("Failed decode %s in %s", + elm->name, td->name); + FREEMEM(opres); + return rv; + } + } + + /* Optionality map is not needed anymore */ + FREEMEM(opres); + + /* + * Deal with extensions. + */ + if(extpresent) { + ssize_t bmlength; + uint8_t *epres; /* Presence of extension members */ + asn_per_data_t epmd; + + bmlength = uper_get_nslength(pd); + if(bmlength < 0) ASN__DECODE_STARVED; + + ASN_DEBUG("Extensions %" ASN_PRI_SSIZE " present in %s", bmlength, td->name); + + epres = (uint8_t *)MALLOC((bmlength + 15) >> 3); + if(!epres) ASN__DECODE_STARVED; + + /* Get the extensions map */ + if(per_get_many_bits(pd, epres, 0, bmlength)) { + FREEMEM(epres); + ASN__DECODE_STARVED; + } + + memset(&epmd, 0, sizeof(epmd)); + epmd.buffer = epres; + epmd.nbits = bmlength; + ASN_DEBUG("Read in extensions bitmap for %s of %ld bits (%x..)", + td->name, (long)bmlength, *epres); + + /* Go over extensions and read them in */ + for(edx = specs->first_extension; edx < td->elements_count; edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + int present; + + /* Fetch the pointer to this member */ + if(elm->flags & ATF_POINTER) { + memb_ptr2 = (void **)((char *)st + elm->memb_offset); + } else { + memb_ptr = (void *)((char *)st + elm->memb_offset); + memb_ptr2 = &memb_ptr; + } + + present = per_get_few_bits(&epmd, 1); + if(present <= 0) { + if(present < 0) break; /* No more extensions */ + continue; + } + + ASN_DEBUG("Decoding member %s in %s %p", elm->name, td->name, + *memb_ptr2); + rv = uper_open_type_get(opt_codec_ctx, elm->type, + elm->encoding_constraints.per_constraints, + memb_ptr2, pd); + if(rv.code != RC_OK) { + FREEMEM(epres); + return rv; + } + } + + /* Skip over overflow extensions which aren't present + * in this system's version of the protocol */ + for(;;) { + ASN_DEBUG("Getting overflow extensions"); + switch(per_get_few_bits(&epmd, 1)) { + case -1: break; + case 0: continue; + default: + if(uper_open_type_skip(opt_codec_ctx, pd)) { + FREEMEM(epres); + ASN__DECODE_STARVED; + } + ASN_DEBUG("Skipped overflow extension"); + continue; + } + break; + } + + FREEMEM(epres); + } + + if(specs->first_extension >= 0) { + unsigned i; + /* Fill DEFAULT members in extensions */ + for(i = specs->roms_count; i < specs->roms_count + specs->aoms_count; + i++) { + asn_TYPE_member_t *elm; + void **memb_ptr2; /* Pointer to member pointer */ + + edx = specs->oms[i]; + elm = &td->elements[edx]; + + if(!elm->default_value_set) continue; + + /* Fetch the pointer to this member */ + if(elm->flags & ATF_POINTER) { + memb_ptr2 = (void **)((char *)st + elm->memb_offset); + if(*memb_ptr2) continue; + } else { + continue; /* Extensions are all optionals */ + } + + /* Set default value */ + if(elm->default_value_set(memb_ptr2)) { + ASN__DECODE_FAILED; + } + } + } + + rv.consumed = 0; + rv.code = RC_OK; + return rv; +} + +static int +SEQUENCE__handle_extensions(const asn_TYPE_descriptor_t *td, const void *sptr, + asn_per_outp_t *po1, asn_per_outp_t *po2) { + const asn_SEQUENCE_specifics_t *specs = + (const asn_SEQUENCE_specifics_t *)td->specifics; + int exts_present = 0; + int exts_count = 0; + size_t edx; + + if(specs->first_extension < 0) { + return 0; + } + + /* Find out which extensions are present */ + for(edx = specs->first_extension; edx < td->elements_count; edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + const void *memb_ptr; /* Pointer to the member */ + const void *const *memb_ptr2; /* Pointer to that pointer */ + int present; + + /* Fetch the pointer to this member */ + if(elm->flags & ATF_POINTER) { + memb_ptr2 = + (const void *const *)((const char *)sptr + elm->memb_offset); + present = (*memb_ptr2 != 0); + } else { + memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); + memb_ptr2 = &memb_ptr; + present = 1; + } + + ASN_DEBUG("checking %s:%s (@%" ASN_PRI_SIZE ") present => %d", elm->name, + elm->type->name, edx, present); + exts_count++; + exts_present += present; + + /* Encode as presence marker */ + if(po1 && per_put_few_bits(po1, present, 1)) { + return -1; + } + /* Encode as open type field */ + if(po2 && present + && uper_open_type_put(elm->type, + elm->encoding_constraints.per_constraints, + *memb_ptr2, po2)) + return -1; + } + + return exts_present ? exts_count : 0; +} + +asn_enc_rval_t +SEQUENCE_encode_uper(const asn_TYPE_descriptor_t *td, + const asn_per_constraints_t *constraints, const void *sptr, + asn_per_outp_t *po) { + const asn_SEQUENCE_specifics_t *specs + = (const asn_SEQUENCE_specifics_t *)td->specifics; + asn_enc_rval_t er; + int n_extensions; + size_t edx; + size_t i; + + (void)constraints; + + if(!sptr) + ASN__ENCODE_FAILED; + + er.encoded = 0; + + ASN_DEBUG("Encoding %s as SEQUENCE (UPER)", td->name); + + /* + * X.691#18.1 Whether structure is extensible + * and whether to encode extensions + */ + if(specs->first_extension < 0) { + n_extensions = 0; /* There are no extensions to encode */ + } else { + n_extensions = SEQUENCE__handle_extensions(td, sptr, 0, 0); + if(n_extensions < 0) ASN__ENCODE_FAILED; + if(per_put_few_bits(po, n_extensions ? 1 : 0, 1)) { + ASN__ENCODE_FAILED; + } + } + + /* Encode a presence bitmap */ + for(i = 0; i < specs->roms_count; i++) { + asn_TYPE_member_t *elm; + const void *memb_ptr; /* Pointer to the member */ + const void *const *memb_ptr2; /* Pointer to that pointer */ + int present; + + edx = specs->oms[i]; + elm = &td->elements[edx]; + + /* Fetch the pointer to this member */ + if(elm->flags & ATF_POINTER) { + memb_ptr2 = + (const void *const *)((const char *)sptr + elm->memb_offset); + present = (*memb_ptr2 != 0); + } else { + memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); + memb_ptr2 = &memb_ptr; + present = 1; + } + + /* Eliminate default values */ + if(present && elm->default_value_cmp + && elm->default_value_cmp(*memb_ptr2) == 0) + present = 0; + + ASN_DEBUG("Element %s %s %s->%s is %s", + elm->flags & ATF_POINTER ? "ptr" : "inline", + elm->default_value_cmp ? "def" : "wtv", + td->name, elm->name, present ? "present" : "absent"); + if(per_put_few_bits(po, present, 1)) + ASN__ENCODE_FAILED; + } + + /* + * Encode the sequence ROOT elements. + */ + ASN_DEBUG("first_extension = %d, elements = %d", specs->first_extension, + td->elements_count); + for(edx = 0; + edx < ((specs->first_extension < 0) ? td->elements_count + : (size_t)specs->first_extension); + edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + const void *memb_ptr; /* Pointer to the member */ + const void *const *memb_ptr2; /* Pointer to that pointer */ + + ASN_DEBUG("About to encode %s", elm->type->name); + + /* Fetch the pointer to this member */ + if(elm->flags & ATF_POINTER) { + memb_ptr2 = + (const void *const *)((const char *)sptr + elm->memb_offset); + if(!*memb_ptr2) { + ASN_DEBUG("Element %s %" ASN_PRI_SIZE " not present", + elm->name, edx); + if(elm->optional) + continue; + /* Mandatory element is missing */ + ASN__ENCODE_FAILED; + } + } else { + memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); + memb_ptr2 = &memb_ptr; + } + + /* Eliminate default values */ + if(elm->default_value_cmp && elm->default_value_cmp(*memb_ptr2) == 0) + continue; + + ASN_DEBUG("Encoding %s->%s:%s", td->name, elm->name, elm->type->name); + er = elm->type->op->uper_encoder( + elm->type, elm->encoding_constraints.per_constraints, *memb_ptr2, + po); + if(er.encoded == -1) return er; + } + + /* No extensions to encode */ + if(!n_extensions) ASN__ENCODED_OK(er); + + ASN_DEBUG("Length of extensions %d bit-map", n_extensions); + /* #18.8. Write down the presence bit-map length. */ + if(uper_put_nslength(po, n_extensions)) + ASN__ENCODE_FAILED; + + ASN_DEBUG("Bit-map of %d elements", n_extensions); + /* #18.7. Encoding the extensions presence bit-map. */ + /* TODO: act upon NOTE in #18.7 for canonical PER */ + if(SEQUENCE__handle_extensions(td, sptr, po, 0) != n_extensions) + ASN__ENCODE_FAILED; + + ASN_DEBUG("Writing %d extensions", n_extensions); + /* #18.9. Encode extensions as open type fields. */ + if(SEQUENCE__handle_extensions(td, sptr, 0, po) != n_extensions) + ASN__ENCODE_FAILED; + + ASN__ENCODED_OK(er); +} + +#endif /* ASN_DISABLE_PER_SUPPORT */ + +int +SEQUENCE_compare(const asn_TYPE_descriptor_t *td, const void *aptr, + const void *bptr) { + size_t edx; + + for(edx = 0; edx < td->elements_count; edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + const void *amemb; + const void *bmemb; + int ret; + + if(elm->flags & ATF_POINTER) { + amemb = + *(const void *const *)((const char *)aptr + elm->memb_offset); + bmemb = + *(const void *const *)((const char *)bptr + elm->memb_offset); + if(!amemb) { + if(!bmemb) continue; + if(elm->default_value_cmp + && elm->default_value_cmp(bmemb) == 0) { + /* A is absent, but B is present and equal to DEFAULT */ + continue; + } + return -1; + } else if(!bmemb) { + if(elm->default_value_cmp + && elm->default_value_cmp(amemb) == 0) { + /* B is absent, but A is present and equal to DEFAULT */ + continue; + } + return 1; + } + } else { + amemb = (const void *)((const char *)aptr + elm->memb_offset); + bmemb = (const void *)((const char *)bptr + elm->memb_offset); + } + + ret = elm->type->op->compare_struct(elm->type, amemb, bmemb); + if(ret != 0) return ret; + } + + return 0; +} + +asn_TYPE_operation_t asn_OP_SEQUENCE = { + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_compare, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, +#ifdef ASN_DISABLE_OER_SUPPORT + 0, + 0, +#else + SEQUENCE_decode_oer, + SEQUENCE_encode_oer, +#endif /* ASN_DISABLE_OER_SUPPORT */ +#ifdef ASN_DISABLE_PER_SUPPORT + 0, + 0, +#else + SEQUENCE_decode_uper, + SEQUENCE_encode_uper, +#endif /* ASN_DISABLE_PER_SUPPORT */ + SEQUENCE_random_fill, + 0 /* Use generic outmost tag fetcher */ +}; + + +asn_random_fill_result_t +SEQUENCE_random_fill(const asn_TYPE_descriptor_t *td, void **sptr, + const asn_encoding_constraints_t *constr, + size_t max_length) { + const asn_SEQUENCE_specifics_t *specs = + (const asn_SEQUENCE_specifics_t *)td->specifics; + asn_random_fill_result_t result_ok = {ARFILL_OK, 0}; + asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0}; + asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0}; + void *st = *sptr; + size_t edx; + + if(max_length == 0) return result_skipped; + + (void)constr; + + if(st == NULL) { + st = CALLOC(1, specs->struct_size); + if(st == NULL) { + return result_failed; + } + } + + for(edx = 0; edx < td->elements_count; edx++) { + const asn_TYPE_member_t *elm = &td->elements[edx]; + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + asn_random_fill_result_t tmpres; + + if(elm->optional && asn_random_between(0, 4) == 2) { + /* Sometimes decide not to fill the optional value */ + continue; + } + + if(elm->flags & ATF_POINTER) { + /* Member is a pointer to another structure */ + memb_ptr2 = (void **)((char *)st + elm->memb_offset); + } else { + memb_ptr = (char *)st + elm->memb_offset; + memb_ptr2 = &memb_ptr; + } + + tmpres = elm->type->op->random_fill( + elm->type, memb_ptr2, &elm->encoding_constraints, + max_length > result_ok.length ? max_length - result_ok.length : 0); + switch(tmpres.code) { + case ARFILL_OK: + result_ok.length += tmpres.length; + continue; + case ARFILL_SKIPPED: + assert(!(elm->flags & ATF_POINTER) || *memb_ptr2 == NULL); + continue; + case ARFILL_FAILED: + if(st == *sptr) { + ASN_STRUCT_RESET(*td, st); + } else { + ASN_STRUCT_FREE(*td, st); + } + return tmpres; + } + } + + *sptr = st; + + return result_ok; +} + diff --git a/Vendor/asn1/include/constr_SEQUENCE.h b/Vendor/asn1/include/constr_SEQUENCE.h new file mode 100644 index 0000000..f9dd4e5 --- /dev/null +++ b/Vendor/asn1/include/constr_SEQUENCE.h @@ -0,0 +1,66 @@ +/*- + * Copyright (c) 2003-2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _CONSTR_SEQUENCE_H_ +#define _CONSTR_SEQUENCE_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct asn_SEQUENCE_specifics_s { + /* + * Target structure description. + */ + unsigned struct_size; /* Size of the target structure. */ + unsigned ctx_offset; /* Offset of the asn_struct_ctx_t member */ + + /* + * Tags to members mapping table (sorted). + */ + const asn_TYPE_tag2member_t *tag2el; + unsigned tag2el_count; + + /* + * Optional members of the extensions root (roms) or additions (aoms). + * Meaningful for PER. + */ + const int *oms; /* Optional MemberS */ + unsigned roms_count; /* Root optional members count */ + unsigned aoms_count; /* Additions optional members count */ + + /* + * Description of an extensions group. + * Root components are clustered at the beginning of the structure, + * whereas extensions are clustered at the end. -1 means not extensible. + */ + signed first_extension; /* First extension addition */ +} asn_SEQUENCE_specifics_t; + + +/* + * A set specialized functions dealing with the SEQUENCE type. + */ +asn_struct_free_f SEQUENCE_free; +asn_struct_print_f SEQUENCE_print; +asn_struct_compare_f SEQUENCE_compare; +asn_constr_check_f SEQUENCE_constraint; +ber_type_decoder_f SEQUENCE_decode_ber; +der_type_encoder_f SEQUENCE_encode_der; +xer_type_decoder_f SEQUENCE_decode_xer; +xer_type_encoder_f SEQUENCE_encode_xer; +oer_type_decoder_f SEQUENCE_decode_oer; +oer_type_encoder_f SEQUENCE_encode_oer; +per_type_decoder_f SEQUENCE_decode_uper; +per_type_encoder_f SEQUENCE_encode_uper; +asn_random_fill_f SEQUENCE_random_fill; +extern asn_TYPE_operation_t asn_OP_SEQUENCE; + +#ifdef __cplusplus +} +#endif + +#endif /* _CONSTR_SEQUENCE_H_ */ diff --git a/Vendor/asn1/include/constr_SEQUENCE_oer.c b/Vendor/asn1/include/constr_SEQUENCE_oer.c new file mode 100644 index 0000000..4f290a1 --- /dev/null +++ b/Vendor/asn1/include/constr_SEQUENCE_oer.c @@ -0,0 +1,561 @@ +/* + * Copyright (c) 2017 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef ASN_DISABLE_OER_SUPPORT + +#include +#include +#include +#include + +/* + * This macro "eats" the part of the buffer which is definitely "consumed", + * i.e. was correctly converted into local representation or rightfully skipped. + */ +#undef ADVANCE +#define ADVANCE(num_bytes) \ + do { \ + size_t num = num_bytes; \ + ptr = ((const char *)ptr) + num; \ + size -= num; \ + consumed_myself += num; \ + } while(0) + +/* + * Switch to the next phase of parsing. + */ +#undef NEXT_PHASE +#undef PHASE_OUT +#define NEXT_PHASE(ctx) \ + do { \ + ctx->phase++; \ + ctx->step = 0; \ + } while(0) + +/* + * Check whether we are inside the extensions group. + */ +#define IN_EXTENSION_GROUP(specs, memb_idx) \ + ((specs)->first_extension >= 0 \ + && (unsigned)(specs)->first_extension <= (memb_idx)) + +#define IN_ROOT_GROUP_PRED(edx) \ + edx < (specs->first_extension < 0 ? td->elements_count \ + : (size_t)specs->first_extension) + +#define FOR_IN_ROOT_GROUP(edx) for(edx = 0; IN_ROOT_GROUP_PRED(edx); edx++) + +/* + * Return a standardized complex structure. + */ +#undef RETURN +#define RETURN(_code) do { \ + rval.code = _code; \ + rval.consumed = consumed_myself;\ + return rval; \ + } while(0) + +/* + * Return pointer to a member. + */ +static void ** +element_ptrptr(void *struct_ptr, asn_TYPE_member_t *elm, void **tmp_save_ptr) { + if(elm->flags & ATF_POINTER) { + /* Member is a pointer to another structure */ + return (void **)((char *)struct_ptr + elm->memb_offset); + } else { + assert(tmp_save_ptr); + *tmp_save_ptr = (void *)((char *)struct_ptr + elm->memb_offset); + return tmp_save_ptr; + } +} + +static const void * +element_ptr(const void *struct_ptr, const asn_TYPE_member_t *elm) { + if(elm->flags & ATF_POINTER) { + /* Member is a pointer to another structure */ + return *(const void *const *)((const char *)struct_ptr + + elm->memb_offset); + } else { + return (const void *)((const char *)struct_ptr + elm->memb_offset); + } +} + +asn_dec_rval_t +SEQUENCE_decode_oer(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, + const asn_oer_constraints_t *constraints, void **struct_ptr, + const void *ptr, size_t size) { + const asn_SEQUENCE_specifics_t *specs = + (const asn_SEQUENCE_specifics_t *)td->specifics; + asn_dec_rval_t rval = {RC_OK, 0}; + void *st = *struct_ptr; /* Target structure */ + asn_struct_ctx_t *ctx; /* Decoder context */ + size_t consumed_myself = 0; /* Consumed bytes from ptr. */ + + (void)constraints; + + if(ASN__STACK_OVERFLOW_CHECK(opt_codec_ctx)) + ASN__DECODE_FAILED; + + /* + * Create the target structure if it is not present already. + */ + if(st == 0) { + st = *struct_ptr = CALLOC(1, specs->struct_size); + if(st == 0) { + RETURN(RC_FAIL); + } + } + + /* + * Restore parsing context. + */ + ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); + + /* + * Start to parse where left previously. + */ + switch(ctx->phase) { + case 0: { + /* + * Fetch preamble. + */ + asn_bit_data_t *preamble; + int has_extensions_bit = (specs->first_extension >= 0); + size_t preamble_bits = (has_extensions_bit + specs->roms_count); + size_t preamble_bytes = ((7 + preamble_bits) >> 3); + + ASN_DEBUG("OER SEQUENCE %s Decoding PHASE 0", td->name); + + ASN_DEBUG( + "Expecting preamble bits %" ASN_PRI_SIZE " for %s (including %d extension bits)", + preamble_bits, td->name, has_extensions_bit); + + if(preamble_bytes > size) { + ASN__DECODE_STARVED; + } + + preamble = asn_bit_data_new_contiguous(ptr, preamble_bits); + if(!preamble) { + RETURN(RC_FAIL); + } + preamble->nboff = has_extensions_bit; + ctx->ptr = preamble; + ADVANCE(preamble_bytes); + } + NEXT_PHASE(ctx); + /* FALL THROUGH */ + case 1: { + /* Decode components of the extension root */ + asn_bit_data_t *preamble = ctx->ptr; + size_t edx; + + ASN_DEBUG("OER SEQUENCE %s Decoding PHASE 1 (Root)", td->name); + + assert(preamble); + + for(edx = (ctx->step >> 1); IN_ROOT_GROUP_PRED(edx); + edx++, ctx->step = (ctx->step & ~1) + 2) { + asn_TYPE_member_t *elm = &td->elements[edx]; + + ASN_DEBUG("Decoding %s->%s", td->name, elm->name); + + assert(!IN_EXTENSION_GROUP(specs, edx)); + + if(ctx->step & 1) { + goto microphase2_decode_continues; + } + + + if(elm->optional) { + int32_t present = asn_get_few_bits(preamble, 1); + if(present < 0) { + ASN_DEBUG("Presence map ended prematurely: %d", present); + RETURN(RC_FAIL); + } else if(present == 0) { + if(elm->default_value_set) { + /* Fill-in DEFAULT */ + void *tmp; + if(elm->default_value_set( + element_ptrptr(st, elm, &tmp))) { + RETURN(RC_FAIL); + } + } + /* The member is not present. */ + continue; + } + /* Present OPTIONAL or DEFAULT component. */ + } + + /* + * MICROPHASE 2: Invoke the member-specific decoder. + */ + ctx->step |= 1; /* Confirm entering next microphase */ + microphase2_decode_continues: + if(elm->flags & ATF_OPEN_TYPE) { + rval = OPEN_TYPE_oer_get(opt_codec_ctx, td, st, elm, ptr, size); + } else { + void *save_memb_ptr; /* Temporary reference. */ + void **memb_ptr2; /* Pointer to a pointer to a memmber */ + + memb_ptr2 = element_ptrptr(st, elm, &save_memb_ptr); + + rval = elm->type->op->oer_decoder( + opt_codec_ctx, elm->type, + elm->encoding_constraints.oer_constraints, memb_ptr2, ptr, + size); + } + switch(rval.code) { + case RC_OK: + ADVANCE(rval.consumed); + break; + case RC_WMORE: + ASN_DEBUG("More bytes needed at element %s \"%s\"", td->name, + elm->name); + ADVANCE(rval.consumed); + RETURN(RC_WMORE); + case RC_FAIL: + ASN_DEBUG("Decoding failed at element %s \"%s\"", td->name, + elm->name); + RETURN(RC_FAIL); + } + } /* for(all root members) */ + + } + NEXT_PHASE(ctx); + /* FALL THROUGH */ + case 2: + assert(ctx->ptr); + { + /* Cleanup preamble. */ + asn_bit_data_t *preamble = ctx->ptr; + asn_bit_data_t *extadds; + int has_extensions_bit = (specs->first_extension >= 0); + int extensions_present = + has_extensions_bit + && (preamble->buffer == NULL + || (((const uint8_t *)preamble->buffer)[0] & 0x80)); + uint8_t unused_bits; + size_t len = 0; + ssize_t len_len; + + ASN_DEBUG("OER SEQUENCE %s Decoding PHASE 2", td->name); + + preamble->buffer = 0; /* Will do extensions_present==1 next time. */ + + if(!extensions_present) { + ctx->phase = 10; + RETURN(RC_OK); + } + + /* + * X.696 (08/2015) #16.1 (c), #16.4 + * Read in the extension addition presence bitmap. + */ + + len_len = oer_fetch_length(ptr, size, &len); + if(len_len > 0) { + ADVANCE(len_len); + } else if(len_len < 0) { + RETURN(RC_FAIL); + } else { + RETURN(RC_WMORE); + } + + if(len == 0) { + /* 16.4.1-2 */ + RETURN(RC_FAIL); + } else if(len > size) { + RETURN(RC_WMORE); + } + + /* Account for unused bits */ + unused_bits = 0x7 & *(const uint8_t *)ptr; + ADVANCE(1); + len--; + if(unused_bits && len == 0) { + RETURN(RC_FAIL); + } + + /* Get the extensions map */ + extadds = asn_bit_data_new_contiguous(ptr, len * 8 - unused_bits); + if(!extadds) { + RETURN(RC_FAIL); + } + FREEMEM(preamble); + ctx->ptr = extadds; + ADVANCE(len); + } + NEXT_PHASE(ctx); + ctx->step = + (specs->first_extension < 0 ? td->elements_count + : (size_t)specs->first_extension); + /* Fall through */ + case 3: + ASN_DEBUG("OER SEQUENCE %s Decoding PHASE 3 (Extensions)", td->name); + for(; ctx->step < (signed)td->elements_count; ctx->step++) { + asn_bit_data_t *extadds = ctx->ptr; + size_t edx = ctx->step; + asn_TYPE_member_t *elm = &td->elements[edx]; + void *tmp_memb_ptr; + void **memb_ptr2 = element_ptrptr(st, elm, &tmp_memb_ptr); + + switch(asn_get_few_bits(extadds, 1)) { + case -1: + /* + * Not every one of our extensions is known to the remote side. + * Continue filling in their defaults though. + */ + /* Fall through */ + case 0: + /* Fill-in DEFAULT */ + if(elm->default_value_set + && elm->default_value_set(memb_ptr2)) { + RETURN(RC_FAIL); + } + continue; + case 1: { + /* Read OER open type */ + ssize_t ot_size = + oer_open_type_get(opt_codec_ctx, elm->type, + elm->encoding_constraints.oer_constraints, + memb_ptr2, ptr, size); + assert(ot_size <= (ssize_t)size); + if(ot_size > 0) { + ADVANCE(ot_size); + } else if(ot_size < 0) { + RETURN(RC_FAIL); + } else { + /* Roll back open type parsing */ + asn_get_undo(extadds, 1); + RETURN(RC_WMORE); + } + break; + } + default: + RETURN(RC_FAIL); + } + } + + NEXT_PHASE(ctx); + /* Fall through */ + case 4: + ASN_DEBUG("OER SEQUENCE %s Decoding PHASE 4", td->name); + /* Read in the rest of Open Types while ignoring them */ + for(;;) { + asn_bit_data_t *extadds = ctx->ptr; + switch(asn_get_few_bits(extadds, 1)) { + case 0: + continue; + case 1: { + ssize_t skipped = oer_open_type_skip(ptr, size); + if(skipped > 0) { + ADVANCE(skipped); + } else if(skipped < 0) { + RETURN(RC_FAIL); + } else { + asn_get_undo(extadds, 1); + RETURN(RC_WMORE); + } + continue; + } + case -1: + /* No more Open Type encoded components */ + break; + default: + RETURN(RC_FAIL); + } + break; + } + } + + RETURN(RC_OK); +} + +/* + * Encode as Canonical OER. + */ +asn_enc_rval_t +SEQUENCE_encode_oer(const asn_TYPE_descriptor_t *td, + const asn_oer_constraints_t *constraints, const void *sptr, + asn_app_consume_bytes_f *cb, void *app_key) { + const asn_SEQUENCE_specifics_t *specs = (const asn_SEQUENCE_specifics_t *)td->specifics; + size_t computed_size = 0; + int has_extensions_bit = (specs->first_extension >= 0); + size_t preamble_bits = (has_extensions_bit + specs->roms_count); + uint32_t has_extensions = 0; + size_t edx; + int ret; + + (void)constraints; + + if(preamble_bits) { + asn_bit_outp_t preamble; + + memset(&preamble, 0, sizeof(preamble)); + preamble.output = cb; + preamble.op_key = app_key; + + if(has_extensions_bit) { + for(edx = specs->first_extension; edx < td->elements_count; edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + const void *memb_ptr = element_ptr(sptr, elm); + if(memb_ptr) { + if(elm->default_value_cmp + && elm->default_value_cmp(memb_ptr) == 0) { + /* Do not encode default values in extensions */ + } else { + has_extensions = 1; + break; + } + } + } + ret = asn_put_few_bits(&preamble, has_extensions, 1); + assert(ret == 0); + if(ret < 0) { + ASN__ENCODE_FAILED; + } + } + + /* + * Encode optional components bitmap. + */ + if(specs->roms_count) { + FOR_IN_ROOT_GROUP(edx) { + asn_TYPE_member_t *elm = &td->elements[edx]; + + if(IN_EXTENSION_GROUP(specs, edx)) break; + + if(elm->optional) { + const void *memb_ptr = element_ptr(sptr, elm); + uint32_t has_component = memb_ptr != NULL; + if(has_component && elm->default_value_cmp + && elm->default_value_cmp(memb_ptr) == 0) { + has_component = 0; + } + ret = asn_put_few_bits(&preamble, has_component, 1); + if(ret < 0) { + ASN__ENCODE_FAILED; + } + } + } + } + + asn_put_aligned_flush(&preamble); + computed_size += preamble.flushed_bytes; + } /* if(preamble_bits) */ + + /* + * Put root components and extensions root. + */ + for(edx = 0; edx < td->elements_count; edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + asn_enc_rval_t er; + const void *memb_ptr; + + if(IN_EXTENSION_GROUP(specs, edx)) break; + + memb_ptr = element_ptr(sptr, elm); + if(memb_ptr) { + if(elm->default_value_cmp + && elm->default_value_cmp(memb_ptr) == 0) { + /* Skip default values in encoding */ + continue; + } + } else { + if(elm->optional) continue; + /* Mandatory element is missing */ + ASN__ENCODE_FAILED; + } + if(!elm->type->op->oer_encoder) { + ASN_DEBUG("OER encoder is not defined for type %s", elm->type->name); + ASN__ENCODE_FAILED; + } + er = elm->type->op->oer_encoder( + elm->type, elm->encoding_constraints.oer_constraints, memb_ptr, cb, + app_key); + if(er.encoded == -1) { + ASN_DEBUG("... while encoding %s member \"%s\"\n", td->name, + elm->name); + return er; + } + computed_size += er.encoded; + } + + /* + * Before encode extensions, encode extensions additions presense bitmap + # X.696 (08/2015) #16.4. + */ + if(has_extensions) { + asn_bit_outp_t extadds; + + /* Special case allowing us to use exactly one byte for #8.6 */ + size_t aoms_length_bits = specs->aoms_count; + size_t aoms_length_bytes = (7 + aoms_length_bits) >> 3; + uint8_t unused_bits = 0x07 & (8 - (aoms_length_bits & 0x07)); + + assert(1 + aoms_length_bytes <= 127); + + memset(&extadds, 0, sizeof(extadds)); + extadds.output = cb; + extadds.op_key = app_key; + + /* #8.6 length determinant */ + ret = asn_put_few_bits(&extadds, (1 + aoms_length_bytes), 8); + if(ret < 0) ASN__ENCODE_FAILED; + + /* Number of unused bytes, #16.4.2 */ + ret = asn_put_few_bits(&extadds, unused_bits, 8); + if(ret < 0) ASN__ENCODE_FAILED; + + /* Encode presence bitmap #16.4.3 */ + for(edx = specs->first_extension; edx < td->elements_count; edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + const void *memb_ptr = element_ptr(sptr, elm); + if(memb_ptr && elm->default_value_cmp + && elm->default_value_cmp(memb_ptr) == 0) { + memb_ptr = 0; /* Do not encode default value. */ + } + ret |= asn_put_few_bits(&extadds, memb_ptr ? 1 : 0, 1); + } + if(ret < 0) ASN__ENCODE_FAILED; + + asn_put_aligned_flush(&extadds); + computed_size += extadds.flushed_bytes; + + /* Now, encode extensions */ + for(edx = specs->first_extension; edx < td->elements_count; edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + const void *memb_ptr = element_ptr(sptr, elm); + + if(memb_ptr) { + if(elm->default_value_cmp + && elm->default_value_cmp(memb_ptr) == 0) { + /* Do not encode default value. */ + } else { + ssize_t wrote = oer_open_type_put( + elm->type, elm->encoding_constraints.oer_constraints, + memb_ptr, cb, app_key); + if(wrote == -1) { + ASN__ENCODE_FAILED; + } + computed_size += wrote; + } + } else if(!elm->optional) { + ASN__ENCODE_FAILED; + } + } + } /* if(has_extensions) */ + + + { + asn_enc_rval_t er = {0, 0, 0}; + er.encoded = computed_size; + ASN__ENCODED_OK(er); + } +} + +#endif /* ASN_DISABLE_OER_SUPPORT */ diff --git a/Vendor/asn1/include/constr_SET_OF.c b/Vendor/asn1/include/constr_SET_OF.c new file mode 100644 index 0000000..96c5c09 --- /dev/null +++ b/Vendor/asn1/include/constr_SET_OF.c @@ -0,0 +1,1348 @@ +/* + * Copyright (c) 2003-2017 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include + +/* + * Number of bytes left for this structure. + * (ctx->left) indicates the number of bytes _transferred_ for the structure. + * (size) contains the number of bytes in the buffer passed. + */ +#define LEFT ((size<(size_t)ctx->left)?size:(size_t)ctx->left) + +/* + * If the subprocessor function returns with an indication that it wants + * more data, it may well be a fatal decoding problem, because the + * size is constrained by the 's L, even if the buffer size allows + * reading more data. + * For example, consider the buffer containing the following TLVs: + * ... + * The TLV length clearly indicates that one byte is expected in V, but + * if the V processor returns with "want more data" even if the buffer + * contains way more data than the V processor have seen. + */ +#define SIZE_VIOLATION (ctx->left >= 0 && (size_t)ctx->left <= size) + +/* + * This macro "eats" the part of the buffer which is definitely "consumed", + * i.e. was correctly converted into local representation or rightfully skipped. + */ +#undef ADVANCE +#define ADVANCE(num_bytes) do { \ + size_t num = num_bytes; \ + ptr = ((const char *)ptr) + num;\ + size -= num; \ + if(ctx->left >= 0) \ + ctx->left -= num; \ + consumed_myself += num; \ + } while(0) + +/* + * Switch to the next phase of parsing. + */ +#undef NEXT_PHASE +#undef PHASE_OUT +#define NEXT_PHASE(ctx) do { \ + ctx->phase++; \ + ctx->step = 0; \ + } while(0) +#define PHASE_OUT(ctx) do { ctx->phase = 10; } while(0) + +/* + * Return a standardized complex structure. + */ +#undef RETURN +#define RETURN(_code) do { \ + rval.code = _code; \ + rval.consumed = consumed_myself;\ + return rval; \ + } while(0) + +/* + * The decoder of the SET OF type. + */ +asn_dec_rval_t +SET_OF_decode_ber(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, void **struct_ptr, + const void *ptr, size_t size, int tag_mode) { + /* + * Bring closer parts of structure description. + */ + const asn_SET_OF_specifics_t *specs = (const asn_SET_OF_specifics_t *)td->specifics; + const asn_TYPE_member_t *elm = td->elements; /* Single one */ + + /* + * Parts of the structure being constructed. + */ + void *st = *struct_ptr; /* Target structure. */ + asn_struct_ctx_t *ctx; /* Decoder context */ + + ber_tlv_tag_t tlv_tag; /* T from TLV */ + asn_dec_rval_t rval; /* Return code from subparsers */ + + ssize_t consumed_myself = 0; /* Consumed bytes from ptr */ + + ASN_DEBUG("Decoding %s as SET OF", td->name); + + /* + * Create the target structure if it is not present already. + */ + if(st == 0) { + st = *struct_ptr = CALLOC(1, specs->struct_size); + if(st == 0) { + RETURN(RC_FAIL); + } + } + + /* + * Restore parsing context. + */ + ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); + + /* + * Start to parse where left previously + */ + switch(ctx->phase) { + case 0: + /* + * PHASE 0. + * Check that the set of tags associated with given structure + * perfectly fits our expectations. + */ + + rval = ber_check_tags(opt_codec_ctx, td, ctx, ptr, size, + tag_mode, 1, &ctx->left, 0); + if(rval.code != RC_OK) { + ASN_DEBUG("%s tagging check failed: %d", + td->name, rval.code); + return rval; + } + + if(ctx->left >= 0) + ctx->left += rval.consumed; /* ?Substracted below! */ + ADVANCE(rval.consumed); + + ASN_DEBUG("Structure consumes %ld bytes, " + "buffer %ld", (long)ctx->left, (long)size); + + NEXT_PHASE(ctx); + /* Fall through */ + case 1: + /* + * PHASE 1. + * From the place where we've left it previously, + * try to decode the next item. + */ + for(;; ctx->step = 0) { + ssize_t tag_len; /* Length of TLV's T */ + + if(ctx->step & 1) + goto microphase2; + + /* + * MICROPHASE 1: Synchronize decoding. + */ + + if(ctx->left == 0) { + ASN_DEBUG("End of SET OF %s", td->name); + /* + * No more things to decode. + * Exit out of here. + */ + PHASE_OUT(ctx); + RETURN(RC_OK); + } + + /* + * Fetch the T from TLV. + */ + tag_len = ber_fetch_tag(ptr, LEFT, &tlv_tag); + switch(tag_len) { + case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); + /* Fall through */ + case -1: RETURN(RC_FAIL); + } + + if(ctx->left < 0 && ((const uint8_t *)ptr)[0] == 0) { + if(LEFT < 2) { + if(SIZE_VIOLATION) + RETURN(RC_FAIL); + else + RETURN(RC_WMORE); + } else if(((const uint8_t *)ptr)[1] == 0) { + /* + * Found the terminator of the + * indefinite length structure. + */ + break; + } + } + + /* Outmost tag may be unknown and cannot be fetched/compared */ + if(elm->tag != (ber_tlv_tag_t)-1) { + if(BER_TAGS_EQUAL(tlv_tag, elm->tag)) { + /* + * The new list member of expected type has arrived. + */ + } else { + ASN_DEBUG("Unexpected tag %s fixed SET OF %s", + ber_tlv_tag_string(tlv_tag), td->name); + ASN_DEBUG("%s SET OF has tag %s", + td->name, ber_tlv_tag_string(elm->tag)); + RETURN(RC_FAIL); + } + } + + /* + * MICROPHASE 2: Invoke the member-specific decoder. + */ + ctx->step |= 1; /* Confirm entering next microphase */ + microphase2: + + /* + * Invoke the member fetch routine according to member's type + */ + rval = elm->type->op->ber_decoder(opt_codec_ctx, + elm->type, &ctx->ptr, ptr, LEFT, 0); + ASN_DEBUG("In %s SET OF %s code %d consumed %d", + td->name, elm->type->name, + rval.code, (int)rval.consumed); + switch(rval.code) { + case RC_OK: + { + asn_anonymous_set_ *list = _A_SET_FROM_VOID(st); + if(ASN_SET_ADD(list, ctx->ptr) != 0) + RETURN(RC_FAIL); + else + ctx->ptr = 0; + } + break; + case RC_WMORE: /* More data expected */ + if(!SIZE_VIOLATION) { + ADVANCE(rval.consumed); + RETURN(RC_WMORE); + } + /* Fall through */ + case RC_FAIL: /* Fatal error */ + ASN_STRUCT_FREE(*elm->type, ctx->ptr); + ctx->ptr = 0; + RETURN(RC_FAIL); + } /* switch(rval) */ + + ADVANCE(rval.consumed); + } /* for(all list members) */ + + NEXT_PHASE(ctx); + case 2: + /* + * Read in all "end of content" TLVs. + */ + while(ctx->left < 0) { + if(LEFT < 2) { + if(LEFT > 0 && ((const char *)ptr)[0] != 0) { + /* Unexpected tag */ + RETURN(RC_FAIL); + } else { + RETURN(RC_WMORE); + } + } + if(((const char *)ptr)[0] == 0 + && ((const char *)ptr)[1] == 0) { + ADVANCE(2); + ctx->left++; + } else { + RETURN(RC_FAIL); + } + } + + PHASE_OUT(ctx); + } + + RETURN(RC_OK); +} + +/* + * Internally visible buffer holding a single encoded element. + */ +struct _el_buffer { + uint8_t *buf; + size_t length; + size_t allocated_size; + unsigned bits_unused; +}; +/* Append bytes to the above structure */ +static int _el_addbytes(const void *buffer, size_t size, void *el_buf_ptr) { + struct _el_buffer *el_buf = (struct _el_buffer *)el_buf_ptr; + + if(el_buf->length + size > el_buf->allocated_size) { + size_t new_size = el_buf->allocated_size ? el_buf->allocated_size : 8; + void *p; + + do { + new_size <<= 2; + } while(el_buf->length + size > new_size); + + p = REALLOC(el_buf->buf, new_size); + if(p) { + el_buf->buf = p; + el_buf->allocated_size = new_size; + } else { + return -1; + } + } + + memcpy(el_buf->buf + el_buf->length, buffer, size); + + el_buf->length += size; + return 0; +} + +static void assert_unused_bits(const struct _el_buffer* p) { + if(p->length) { + assert((p->buf[p->length-1] & ~(0xff << p->bits_unused)) == 0); + } else { + assert(p->bits_unused == 0); + } +} + +static int _el_buf_cmp(const void *ap, const void *bp) { + const struct _el_buffer *a = (const struct _el_buffer *)ap; + const struct _el_buffer *b = (const struct _el_buffer *)bp; + size_t common_len; + int ret = 0; + + if(a->length < b->length) + common_len = a->length; + else + common_len = b->length; + + if (a->buf && b->buf) { + ret = memcmp(a->buf, b->buf, common_len); + } + if(ret == 0) { + if(a->length < b->length) + ret = -1; + else if(a->length > b->length) + ret = 1; + /* Ignore unused bits. */ + assert_unused_bits(a); + assert_unused_bits(b); + } + + return ret; +} + +static void +SET_OF__encode_sorted_free(struct _el_buffer *el_buf, size_t count) { + size_t i; + + for(i = 0; i < count; i++) { + FREEMEM(el_buf[i].buf); + } + + FREEMEM(el_buf); +} + +enum SET_OF__encode_method { + SOES_DER, /* Distinguished Encoding Rules */ + SOES_CUPER /* Canonical Unaligned Packed Encoding Rules */ +}; + +static struct _el_buffer * +SET_OF__encode_sorted(const asn_TYPE_member_t *elm, + const asn_anonymous_set_ *list, + enum SET_OF__encode_method method) { + static struct _el_buffer *encoded_els; + int edx; + + encoded_els = + (struct _el_buffer *)CALLOC(list->count, sizeof(encoded_els[0])); + if(encoded_els == NULL) { + return NULL; + } + + /* + * Encode all members. + */ + for(edx = 0; edx < list->count; edx++) { + const void *memb_ptr = list->array[edx]; + struct _el_buffer *encoding_el = &encoded_els[edx]; + asn_enc_rval_t erval; + + if(!memb_ptr) break; + + /* + * Encode the member into the prepared space. + */ + switch(method) { + case SOES_DER: + erval = elm->type->op->der_encoder(elm->type, memb_ptr, 0, elm->tag, + _el_addbytes, encoding_el); + break; + case SOES_CUPER: + erval = uper_encode(elm->type, + elm->encoding_constraints.per_constraints, + memb_ptr, _el_addbytes, encoding_el); + if(erval.encoded != -1) { + size_t extra_bits = erval.encoded % 8; + assert(encoding_el->length == (size_t)(erval.encoded + 7) / 8); + encoding_el->bits_unused = (8 - extra_bits) & 0x7; + } + break; + default: + assert(!"Unreachable"); + break; + } + if(erval.encoded < 0) break; + } + + if(edx == list->count) { + /* + * Sort the encoded elements according to their encoding. + */ + qsort(encoded_els, list->count, sizeof(encoded_els[0]), _el_buf_cmp); + + return encoded_els; + } else { + SET_OF__encode_sorted_free(encoded_els, edx); + return NULL; + } +} + + +/* + * The DER encoder of the SET OF type. + */ +asn_enc_rval_t +SET_OF_encode_der(const asn_TYPE_descriptor_t *td, const void *sptr, + int tag_mode, ber_tlv_tag_t tag, asn_app_consume_bytes_f *cb, + void *app_key) { + const asn_TYPE_member_t *elm = td->elements; + const asn_anonymous_set_ *list = _A_CSET_FROM_VOID(sptr); + size_t computed_size = 0; + ssize_t encoding_size = 0; + struct _el_buffer *encoded_els; + int edx; + + ASN_DEBUG("Estimating size for SET OF %s", td->name); + + /* + * Gather the length of the underlying members sequence. + */ + for(edx = 0; edx < list->count; edx++) { + void *memb_ptr = list->array[edx]; + asn_enc_rval_t erval; + + if(!memb_ptr) ASN__ENCODE_FAILED; + + erval = + elm->type->op->der_encoder(elm->type, memb_ptr, 0, elm->tag, 0, 0); + if(erval.encoded == -1) return erval; + computed_size += erval.encoded; + } + + + /* + * Encode the TLV for the sequence itself. + */ + encoding_size = + der_write_tags(td, computed_size, tag_mode, 1, tag, cb, app_key); + if(encoding_size < 0) { + ASN__ENCODE_FAILED; + } + computed_size += encoding_size; + + if(!cb || list->count == 0) { + asn_enc_rval_t erval; + erval.encoded = computed_size; + ASN__ENCODED_OK(erval); + } + + ASN_DEBUG("Encoding members of %s SET OF", td->name); + + /* + * DER mandates dynamic sorting of the SET OF elements + * according to their encodings. Build an array of the + * encoded elements. + */ + encoded_els = SET_OF__encode_sorted(elm, list, SOES_DER); + + /* + * Report encoded elements to the application. + * Dispose of temporary sorted members table. + */ + for(edx = 0; edx < list->count; edx++) { + struct _el_buffer *encoded_el = &encoded_els[edx]; + /* Report encoded chunks to the application */ + if(cb(encoded_el->buf, encoded_el->length, app_key) < 0) { + break; + } else { + encoding_size += encoded_el->length; + } + } + + SET_OF__encode_sorted_free(encoded_els, list->count); + + if(edx == list->count) { + asn_enc_rval_t erval; + assert(computed_size == (size_t)encoding_size); + erval.encoded = computed_size; + ASN__ENCODED_OK(erval); + } else { + ASN__ENCODE_FAILED; + } +} + +#undef XER_ADVANCE +#define XER_ADVANCE(num_bytes) do { \ + size_t num = num_bytes; \ + buf_ptr = ((const char *)buf_ptr) + num;\ + size -= num; \ + consumed_myself += num; \ + } while(0) + +/* + * Decode the XER (XML) data. + */ +asn_dec_rval_t +SET_OF_decode_xer(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, void **struct_ptr, + const char *opt_mname, const void *buf_ptr, size_t size) { + /* + * Bring closer parts of structure description. + */ + const asn_SET_OF_specifics_t *specs = (const asn_SET_OF_specifics_t *)td->specifics; + const asn_TYPE_member_t *element = td->elements; + const char *elm_tag; + const char *xml_tag = opt_mname ? opt_mname : td->xml_tag; + + /* + * ... and parts of the structure being constructed. + */ + void *st = *struct_ptr; /* Target structure. */ + asn_struct_ctx_t *ctx; /* Decoder context */ + + asn_dec_rval_t rval; /* Return value from a decoder */ + ssize_t consumed_myself = 0; /* Consumed bytes from ptr */ + + /* + * Create the target structure if it is not present already. + */ + if(st == 0) { + st = *struct_ptr = CALLOC(1, specs->struct_size); + if(st == 0) RETURN(RC_FAIL); + } + + /* Which tag is expected for the downstream */ + if(specs->as_XMLValueList) { + elm_tag = (specs->as_XMLValueList == 1) ? 0 : ""; + } else { + elm_tag = (*element->name) + ? element->name : element->type->xml_tag; + } + + /* + * Restore parsing context. + */ + ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); + + /* + * Phases of XER/XML processing: + * Phase 0: Check that the opening tag matches our expectations. + * Phase 1: Processing body and reacting on closing tag. + * Phase 2: Processing inner type. + */ + for(; ctx->phase <= 2;) { + pxer_chunk_type_e ch_type; /* XER chunk type */ + ssize_t ch_size; /* Chunk size */ + xer_check_tag_e tcv; /* Tag check value */ + + /* + * Go inside the inner member of a set. + */ + if(ctx->phase == 2) { + asn_dec_rval_t tmprval; + + /* Invoke the inner type decoder, m.b. multiple times */ + ASN_DEBUG("XER/SET OF element [%s]", elm_tag); + tmprval = element->type->op->xer_decoder(opt_codec_ctx, + element->type, &ctx->ptr, elm_tag, + buf_ptr, size); + if(tmprval.code == RC_OK) { + asn_anonymous_set_ *list = _A_SET_FROM_VOID(st); + if(ASN_SET_ADD(list, ctx->ptr) != 0) + RETURN(RC_FAIL); + ctx->ptr = 0; + XER_ADVANCE(tmprval.consumed); + } else { + XER_ADVANCE(tmprval.consumed); + RETURN(tmprval.code); + } + ctx->phase = 1; /* Back to body processing */ + ASN_DEBUG("XER/SET OF phase => %d", ctx->phase); + /* Fall through */ + } + + /* + * Get the next part of the XML stream. + */ + ch_size = xer_next_token(&ctx->context, + buf_ptr, size, &ch_type); + if(ch_size == -1) { + RETURN(RC_FAIL); + } else { + switch(ch_type) { + case PXER_WMORE: + RETURN(RC_WMORE); + case PXER_COMMENT: /* Got XML comment */ + case PXER_TEXT: /* Ignore free-standing text */ + XER_ADVANCE(ch_size); /* Skip silently */ + continue; + case PXER_TAG: + break; /* Check the rest down there */ + } + } + + tcv = xer_check_tag(buf_ptr, ch_size, xml_tag); + ASN_DEBUG("XER/SET OF: tcv = %d, ph=%d t=%s", + tcv, ctx->phase, xml_tag); + switch(tcv) { + case XCT_CLOSING: + if(ctx->phase == 0) break; + ctx->phase = 0; + /* Fall through */ + case XCT_BOTH: + if(ctx->phase == 0) { + /* No more things to decode */ + XER_ADVANCE(ch_size); + ctx->phase = 3; /* Phase out */ + RETURN(RC_OK); + } + /* Fall through */ + case XCT_OPENING: + if(ctx->phase == 0) { + XER_ADVANCE(ch_size); + ctx->phase = 1; /* Processing body phase */ + continue; + } + /* Fall through */ + case XCT_UNKNOWN_OP: + case XCT_UNKNOWN_BO: + + ASN_DEBUG("XER/SET OF: tcv=%d, ph=%d", tcv, ctx->phase); + if(ctx->phase == 1) { + /* + * Process a single possible member. + */ + ctx->phase = 2; + continue; + } + /* Fall through */ + default: + break; + } + + ASN_DEBUG("Unexpected XML tag in SET OF"); + break; + } + + ctx->phase = 3; /* "Phase out" on hard failure */ + RETURN(RC_FAIL); +} + + + +typedef struct xer_tmp_enc_s { + void *buffer; + size_t offset; + size_t size; +} xer_tmp_enc_t; +static int +SET_OF_encode_xer_callback(const void *buffer, size_t size, void *key) { + xer_tmp_enc_t *t = (xer_tmp_enc_t *)key; + if(t->offset + size >= t->size) { + size_t newsize = (t->size << 2) + size; + void *p = REALLOC(t->buffer, newsize); + if(!p) return -1; + t->buffer = p; + t->size = newsize; + } + memcpy((char *)t->buffer + t->offset, buffer, size); + t->offset += size; + return 0; +} +static int +SET_OF_xer_order(const void *aptr, const void *bptr) { + const xer_tmp_enc_t *a = (const xer_tmp_enc_t *)aptr; + const xer_tmp_enc_t *b = (const xer_tmp_enc_t *)bptr; + size_t minlen = a->offset; + int ret; + if(b->offset < minlen) minlen = b->offset; + /* Well-formed UTF-8 has this nice lexicographical property... */ + ret = memcmp(a->buffer, b->buffer, minlen); + if(ret != 0) return ret; + if(a->offset == b->offset) + return 0; + if(a->offset == minlen) + return -1; + return 1; +} + + +asn_enc_rval_t +SET_OF_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, + enum xer_encoder_flags_e flags, asn_app_consume_bytes_f *cb, + void *app_key) { + asn_enc_rval_t er; + const asn_SET_OF_specifics_t *specs = (const asn_SET_OF_specifics_t *)td->specifics; + const asn_TYPE_member_t *elm = td->elements; + const asn_anonymous_set_ *list = _A_CSET_FROM_VOID(sptr); + const char *mname = specs->as_XMLValueList + ? 0 : ((*elm->name) ? elm->name : elm->type->xml_tag); + size_t mlen = mname ? strlen(mname) : 0; + int xcan = (flags & XER_F_CANONICAL); + xer_tmp_enc_t *encs = 0; + size_t encs_count = 0; + void *original_app_key = app_key; + asn_app_consume_bytes_f *original_cb = cb; + int i; + + if(!sptr) ASN__ENCODE_FAILED; + + if(xcan) { + encs = (xer_tmp_enc_t *)MALLOC(list->count * sizeof(encs[0])); + if(!encs) ASN__ENCODE_FAILED; + cb = SET_OF_encode_xer_callback; + } + + er.encoded = 0; + + for(i = 0; i < list->count; i++) { + asn_enc_rval_t tmper; + + void *memb_ptr = list->array[i]; + if(!memb_ptr) continue; + + if(encs) { + memset(&encs[encs_count], 0, sizeof(encs[0])); + app_key = &encs[encs_count]; + encs_count++; + } + + if(mname) { + if(!xcan) ASN__TEXT_INDENT(1, ilevel); + ASN__CALLBACK3("<", 1, mname, mlen, ">", 1); + } + + if(!xcan && specs->as_XMLValueList == 1) + ASN__TEXT_INDENT(1, ilevel + 1); + tmper = elm->type->op->xer_encoder(elm->type, memb_ptr, + ilevel + (specs->as_XMLValueList != 2), + flags, cb, app_key); + if(tmper.encoded == -1) return tmper; + er.encoded += tmper.encoded; + if(tmper.encoded == 0 && specs->as_XMLValueList) { + const char *name = elm->type->xml_tag; + size_t len = strlen(name); + ASN__CALLBACK3("<", 1, name, len, "/>", 2); + } + + if(mname) { + ASN__CALLBACK3("", 1); + } + + } + + if(!xcan) ASN__TEXT_INDENT(1, ilevel - 1); + + if(encs) { + xer_tmp_enc_t *enc = encs; + xer_tmp_enc_t *end = encs + encs_count; + ssize_t control_size = 0; + + er.encoded = 0; + cb = original_cb; + app_key = original_app_key; + qsort(encs, encs_count, sizeof(encs[0]), SET_OF_xer_order); + + for(; enc < end; enc++) { + ASN__CALLBACK(enc->buffer, enc->offset); + FREEMEM(enc->buffer); + enc->buffer = 0; + control_size += enc->offset; + } + assert(control_size == er.encoded); + } + + goto cleanup; +cb_failed: + ASN__ENCODE_FAILED; +cleanup: + if(encs) { + size_t n; + for(n = 0; n < encs_count; n++) { + FREEMEM(encs[n].buffer); + } + FREEMEM(encs); + } + ASN__ENCODED_OK(er); +} + +int +SET_OF_print(const asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_TYPE_member_t *elm = td->elements; + const asn_anonymous_set_ *list = _A_CSET_FROM_VOID(sptr); + int ret; + int i; + + if(!sptr) return (cb("", 8, app_key) < 0) ? -1 : 0; + + /* Dump preamble */ + if(cb(td->name, strlen(td->name), app_key) < 0 + || cb(" ::= {", 6, app_key) < 0) + return -1; + + for(i = 0; i < list->count; i++) { + const void *memb_ptr = list->array[i]; + if(!memb_ptr) continue; + + _i_INDENT(1); + + ret = elm->type->op->print_struct(elm->type, memb_ptr, + ilevel + 1, cb, app_key); + if(ret) return ret; + } + + ilevel--; + _i_INDENT(1); + + return (cb("}", 1, app_key) < 0) ? -1 : 0; +} + +void +SET_OF_free(const asn_TYPE_descriptor_t *td, void *ptr, + enum asn_struct_free_method method) { + if(td && ptr) { + const asn_SET_OF_specifics_t *specs; + asn_TYPE_member_t *elm = td->elements; + asn_anonymous_set_ *list = _A_SET_FROM_VOID(ptr); + asn_struct_ctx_t *ctx; /* Decoder context */ + int i; + + /* + * Could not use set_of_empty() because of (*free) + * incompatibility. + */ + for(i = 0; i < list->count; i++) { + void *memb_ptr = list->array[i]; + if(memb_ptr) + ASN_STRUCT_FREE(*elm->type, memb_ptr); + } + list->count = 0; /* No meaningful elements left */ + + asn_set_empty(list); /* Remove (list->array) */ + + specs = (const asn_SET_OF_specifics_t *)td->specifics; + ctx = (asn_struct_ctx_t *)((char *)ptr + specs->ctx_offset); + if(ctx->ptr) { + ASN_STRUCT_FREE(*elm->type, ctx->ptr); + ctx->ptr = 0; + } + + switch(method) { + case ASFM_FREE_EVERYTHING: + FREEMEM(ptr); + break; + case ASFM_FREE_UNDERLYING: + break; + case ASFM_FREE_UNDERLYING_AND_RESET: + memset(ptr, 0, specs->struct_size); + break; + } + } +} + +int +SET_OF_constraint(const asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + const asn_TYPE_member_t *elm = td->elements; + asn_constr_check_f *constr; + const asn_anonymous_set_ *list = _A_CSET_FROM_VOID(sptr); + int i; + + if(!sptr) { + ASN__CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + constr = elm->encoding_constraints.general_constraints; + if(!constr) constr = elm->type->encoding_constraints.general_constraints; + + /* + * Iterate over the members of an array. + * Validate each in turn, until one fails. + */ + for(i = 0; i < list->count; i++) { + const void *memb_ptr = list->array[i]; + int ret; + + if(!memb_ptr) continue; + + ret = constr(elm->type, memb_ptr, ctfailcb, app_key); + if(ret) return ret; + } + + return 0; +} + +#ifndef ASN_DISABLE_PER_SUPPORT + +asn_dec_rval_t +SET_OF_decode_uper(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, + const asn_per_constraints_t *constraints, void **sptr, + asn_per_data_t *pd) { + asn_dec_rval_t rv; + const asn_SET_OF_specifics_t *specs = (const asn_SET_OF_specifics_t *)td->specifics; + const asn_TYPE_member_t *elm = td->elements; /* Single one */ + void *st = *sptr; + asn_anonymous_set_ *list; + const asn_per_constraint_t *ct; + int repeat = 0; + ssize_t nelems; + + if(ASN__STACK_OVERFLOW_CHECK(opt_codec_ctx)) + ASN__DECODE_FAILED; + + /* + * Create the target structure if it is not present already. + */ + if(!st) { + st = *sptr = CALLOC(1, specs->struct_size); + if(!st) ASN__DECODE_FAILED; + } + list = _A_SET_FROM_VOID(st); + + /* Figure out which constraints to use */ + if(constraints) ct = &constraints->size; + else if(td->encoding_constraints.per_constraints) + ct = &td->encoding_constraints.per_constraints->size; + else ct = 0; + + if(ct && ct->flags & APC_EXTENSIBLE) { + int value = per_get_few_bits(pd, 1); + if(value < 0) ASN__DECODE_STARVED; + if(value) ct = 0; /* Not restricted! */ + } + + if(ct && ct->effective_bits >= 0) { + /* X.691, #19.5: No length determinant */ + nelems = per_get_few_bits(pd, ct->effective_bits); + ASN_DEBUG("Preparing to fetch %ld+%ld elements from %s", + (long)nelems, ct->lower_bound, td->name); + if(nelems < 0) ASN__DECODE_STARVED; + nelems += ct->lower_bound; + } else { + nelems = -1; + } + + do { + int i; + if(nelems < 0) { + nelems = uper_get_length(pd, -1, 0, &repeat); + ASN_DEBUG("Got to decode %" ASN_PRI_SSIZE " elements (eff %d)", + nelems, (int)(ct ? ct->effective_bits : -1)); + if(nelems < 0) ASN__DECODE_STARVED; + } + + for(i = 0; i < nelems; i++) { + void *ptr = 0; + ASN_DEBUG("SET OF %s decoding", elm->type->name); + rv = elm->type->op->uper_decoder(opt_codec_ctx, elm->type, + elm->encoding_constraints.per_constraints, &ptr, pd); + ASN_DEBUG("%s SET OF %s decoded %d, %p", + td->name, elm->type->name, rv.code, ptr); + if(rv.code == RC_OK) { + if(ASN_SET_ADD(list, ptr) == 0) { + if(rv.consumed == 0 && nelems > 200) { + /* Protect from SET OF NULL compression bombs. */ + ASN__DECODE_FAILED; + } + continue; + } + ASN_DEBUG("Failed to add element into %s", + td->name); + /* Fall through */ + rv.code = RC_FAIL; + } else { + ASN_DEBUG("Failed decoding %s of %s (SET OF)", + elm->type->name, td->name); + } + if(ptr) ASN_STRUCT_FREE(*elm->type, ptr); + return rv; + } + + nelems = -1; /* Allow uper_get_length() */ + } while(repeat); + + ASN_DEBUG("Decoded %s as SET OF", td->name); + + rv.code = RC_OK; + rv.consumed = 0; + return rv; +} + +asn_enc_rval_t +SET_OF_encode_uper(const asn_TYPE_descriptor_t *td, + const asn_per_constraints_t *constraints, const void *sptr, + asn_per_outp_t *po) { + const asn_anonymous_set_ *list; + const asn_per_constraint_t *ct; + const asn_TYPE_member_t *elm = td->elements; + struct _el_buffer *encoded_els; + asn_enc_rval_t er; + size_t encoded_edx; + + if(!sptr) ASN__ENCODE_FAILED; + + list = _A_CSET_FROM_VOID(sptr); + + er.encoded = 0; + + ASN_DEBUG("Encoding %s as SEQUENCE OF (%d)", td->name, list->count); + + if(constraints) ct = &constraints->size; + else if(td->encoding_constraints.per_constraints) + ct = &td->encoding_constraints.per_constraints->size; + else ct = 0; + + /* If extensible constraint, check if size is in root */ + if(ct) { + int not_in_root = + (list->count < ct->lower_bound || list->count > ct->upper_bound); + ASN_DEBUG("lb %ld ub %ld %s", ct->lower_bound, ct->upper_bound, + ct->flags & APC_EXTENSIBLE ? "ext" : "fix"); + if(ct->flags & APC_EXTENSIBLE) { + /* Declare whether size is in extension root */ + if(per_put_few_bits(po, not_in_root, 1)) ASN__ENCODE_FAILED; + if(not_in_root) ct = 0; + } else if(not_in_root && ct->effective_bits >= 0) { + ASN__ENCODE_FAILED; + } + + } + + if(ct && ct->effective_bits >= 0) { + /* X.691, #19.5: No length determinant */ + if(per_put_few_bits(po, list->count - ct->lower_bound, + ct->effective_bits)) + ASN__ENCODE_FAILED; + } else if(list->count == 0) { + /* When the list is empty add only the length determinant + * X.691, #20.6 and #11.9.4.1 + */ + if (uper_put_length(po, 0, 0)) { + ASN__ENCODE_FAILED; + } + ASN__ENCODED_OK(er); + } + + + /* + * Canonical UPER #22.1 mandates dynamic sorting of the SET OF elements + * according to their encodings. Build an array of the encoded elements. + */ + encoded_els = SET_OF__encode_sorted(elm, list, SOES_CUPER); + + for(encoded_edx = 0; (ssize_t)encoded_edx < list->count;) { + ssize_t may_encode; + size_t edx; + int need_eom = 0; + + if(ct && ct->effective_bits >= 0) { + may_encode = list->count; + } else { + may_encode = + uper_put_length(po, list->count - encoded_edx, &need_eom); + if(may_encode < 0) ASN__ENCODE_FAILED; + } + + for(edx = encoded_edx; edx < encoded_edx + may_encode; edx++) { + const struct _el_buffer *el = &encoded_els[edx]; + if(asn_put_many_bits(po, el->buf, + (8 * el->length) - el->bits_unused) < 0) { + break; + } + } + + if(need_eom && uper_put_length(po, 0, 0)) + ASN__ENCODE_FAILED; /* End of Message length */ + + encoded_edx += may_encode; + } + + SET_OF__encode_sorted_free(encoded_els, list->count); + + if((ssize_t)encoded_edx == list->count) { + ASN__ENCODED_OK(er); + } else { + ASN__ENCODE_FAILED; + } +} + + +#endif /* ASN_DISABLE_PER_SUPPORT */ + +struct comparable_ptr { + const asn_TYPE_descriptor_t *td; + const void *sptr; +}; + +static int +SET_OF__compare_cb(const void *aptr, const void *bptr) { + const struct comparable_ptr *a = aptr; + const struct comparable_ptr *b = bptr; + assert(a->td == b->td); + return a->td->op->compare_struct(a->td, a->sptr, b->sptr); +} + +int +SET_OF_compare(const asn_TYPE_descriptor_t *td, const void *aptr, + const void *bptr) { + const asn_anonymous_set_ *a = _A_CSET_FROM_VOID(aptr); + const asn_anonymous_set_ *b = _A_CSET_FROM_VOID(bptr); + + if(a && b) { + struct comparable_ptr *asorted; + struct comparable_ptr *bsorted; + ssize_t common_length; + ssize_t idx; + + if(a->count == 0) { + if(b->count) return -1; + return 0; + } else if(b->count == 0) { + return 1; + } + + asorted = MALLOC(a->count * sizeof(asorted[0])); + bsorted = MALLOC(b->count * sizeof(bsorted[0])); + if(!asorted || !bsorted) { + FREEMEM(asorted); + FREEMEM(bsorted); + return -1; + } + + for(idx = 0; idx < a->count; idx++) { + asorted[idx].td = td->elements->type; + asorted[idx].sptr = a->array[idx]; + } + + for(idx = 0; idx < b->count; idx++) { + bsorted[idx].td = td->elements->type; + bsorted[idx].sptr = b->array[idx]; + } + + qsort(asorted, a->count, sizeof(asorted[0]), SET_OF__compare_cb); + qsort(bsorted, b->count, sizeof(bsorted[0]), SET_OF__compare_cb); + + common_length = (a->count < b->count ? a->count : b->count); + for(idx = 0; idx < common_length; idx++) { + int ret = td->elements->type->op->compare_struct( + td->elements->type, asorted[idx].sptr, bsorted[idx].sptr); + if(ret) { + FREEMEM(asorted); + FREEMEM(bsorted); + return ret; + } + } + + FREEMEM(asorted); + FREEMEM(bsorted); + + if(idx < b->count) /* more elements in b */ + return -1; /* a is shorter, so put it first */ + if(idx < a->count) return 1; + } else if(!a) { + return -1; + } else if(!b) { + return 1; + } + + return 0; +} + + +asn_TYPE_operation_t asn_OP_SET_OF = { + SET_OF_free, + SET_OF_print, + SET_OF_compare, + SET_OF_decode_ber, + SET_OF_encode_der, + SET_OF_decode_xer, + SET_OF_encode_xer, +#ifdef ASN_DISABLE_OER_SUPPORT + 0, + 0, +#else + SET_OF_decode_oer, + SET_OF_encode_oer, +#endif +#ifdef ASN_DISABLE_PER_SUPPORT + 0, + 0, +#else + SET_OF_decode_uper, + SET_OF_encode_uper, +#endif /* ASN_DISABLE_PER_SUPPORT */ + SET_OF_random_fill, + 0 /* Use generic outmost tag fetcher */ +}; + + +asn_random_fill_result_t +SET_OF_random_fill(const asn_TYPE_descriptor_t *td, void **sptr, + const asn_encoding_constraints_t *constraints, + size_t max_length) { + const asn_SET_OF_specifics_t *specs = + (const asn_SET_OF_specifics_t *)td->specifics; + asn_random_fill_result_t res_ok = {ARFILL_OK, 0}; + asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0}; + asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0}; + const asn_TYPE_member_t *elm = td->elements; + void *st = *sptr; + long max_elements = 5; + long slb = 0; /* Lower size bound */ + long sub = 0; /* Upper size bound */ + size_t rnd_len; + + if(max_length == 0) return result_skipped; + + if(st == NULL) { + st = (*sptr = CALLOC(1, specs->struct_size)); + if(st == NULL) { + return result_failed; + } + } + + switch(asn_random_between(0, 6)) { + case 0: max_elements = 0; break; + case 1: max_elements = 1; break; + case 2: max_elements = 5; break; + case 3: max_elements = max_length; break; + case 4: max_elements = max_length / 2; break; + case 5: max_elements = max_length / 4; break; + default: break; + } + sub = slb + max_elements; + + if(!constraints || !constraints->per_constraints) + constraints = &td->encoding_constraints; + if(constraints->per_constraints) { + const asn_per_constraint_t *pc = &constraints->per_constraints->size; + if(pc->flags & APC_SEMI_CONSTRAINED) { + slb = pc->lower_bound; + sub = pc->lower_bound + max_elements; + } else if(pc->flags & APC_CONSTRAINED) { + slb = pc->lower_bound; + sub = pc->upper_bound; + if(sub - slb > max_elements) sub = slb + max_elements; + } + } + + /* Bias towards edges of allowed space */ + switch(asn_random_between(-1, 4)) { + default: + case -1: + /* Prepare lengths somewhat outside of constrained range. */ + if(constraints->per_constraints + && (constraints->per_constraints->size.flags & APC_EXTENSIBLE)) { + switch(asn_random_between(0, 5)) { + default: + case 0: + rnd_len = 0; + break; + case 1: + if(slb > 0) { + rnd_len = slb - 1; + } else { + rnd_len = 0; + } + break; + case 2: + rnd_len = asn_random_between(0, slb); + break; + case 3: + if(sub < (ssize_t)max_length) { + rnd_len = sub + 1; + } else { + rnd_len = max_length; + } + break; + case 4: + if(sub < (ssize_t)max_length) { + rnd_len = asn_random_between(sub + 1, max_length); + } else { + rnd_len = max_length; + } + break; + case 5: + rnd_len = max_length; + break; + } + break; + } + /* Fall through */ + case 0: + rnd_len = asn_random_between(slb, sub); + break; + case 1: + if(slb < sub) { + rnd_len = asn_random_between(slb + 1, sub); + break; + } + /* Fall through */ + case 2: + rnd_len = asn_random_between(slb, slb); + break; + case 3: + if(slb < sub) { + rnd_len = asn_random_between(slb, sub - 1); + break; + } + /* Fall through */ + case 4: + rnd_len = asn_random_between(sub, sub); + break; + } + + for(; rnd_len > 0; rnd_len--) { + asn_anonymous_set_ *list = _A_SET_FROM_VOID(st); + void *ptr = 0; + asn_random_fill_result_t tmpres = elm->type->op->random_fill( + elm->type, &ptr, &elm->encoding_constraints, + (max_length > res_ok.length ? max_length - res_ok.length : 0) + / rnd_len); + switch(tmpres.code) { + case ARFILL_OK: + ASN_SET_ADD(list, ptr); + res_ok.length += tmpres.length; + break; + case ARFILL_SKIPPED: + break; + case ARFILL_FAILED: + assert(ptr == 0); + return tmpres; + } + } + + return res_ok; +} + diff --git a/Vendor/asn1/include/constr_SET_OF.h b/Vendor/asn1/include/constr_SET_OF.h new file mode 100644 index 0000000..f32e607 --- /dev/null +++ b/Vendor/asn1/include/constr_SET_OF.h @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 2003-2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef CONSTR_SET_OF_H +#define CONSTR_SET_OF_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct asn_SET_OF_specifics_s { + /* + * Target structure description. + */ + unsigned struct_size; /* Size of the target structure. */ + unsigned ctx_offset; /* Offset of the asn_struct_ctx_t member */ + + /* XER-specific stuff */ + int as_XMLValueList; /* The member type must be encoded like this */ +} asn_SET_OF_specifics_t; + +/* + * A set specialized functions dealing with the SET OF type. + */ +asn_struct_free_f SET_OF_free; +asn_struct_print_f SET_OF_print; +asn_struct_compare_f SET_OF_compare; +asn_constr_check_f SET_OF_constraint; +ber_type_decoder_f SET_OF_decode_ber; +der_type_encoder_f SET_OF_encode_der; +xer_type_decoder_f SET_OF_decode_xer; +xer_type_encoder_f SET_OF_encode_xer; +oer_type_decoder_f SET_OF_decode_oer; +oer_type_encoder_f SET_OF_encode_oer; +per_type_decoder_f SET_OF_decode_uper; +per_type_encoder_f SET_OF_encode_uper; +asn_random_fill_f SET_OF_random_fill; +extern asn_TYPE_operation_t asn_OP_SET_OF; + +#ifdef __cplusplus +} +#endif + +#endif /* CONSTR_SET_OF_H */ diff --git a/Vendor/asn1/include/constr_SET_OF_oer.c b/Vendor/asn1/include/constr_SET_OF_oer.c new file mode 100644 index 0000000..88d7a2a --- /dev/null +++ b/Vendor/asn1/include/constr_SET_OF_oer.c @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2017 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef ASN_DISABLE_OER_SUPPORT + +#include +#include +#include +#include + +/* + * This macro "eats" the part of the buffer which is definitely "consumed", + * i.e. was correctly converted into local representation or rightfully skipped. + */ +#undef ADVANCE +#define ADVANCE(num_bytes) \ + do { \ + size_t num = num_bytes; \ + ptr = ((const char *)ptr) + num; \ + size -= num; \ + consumed_myself += num; \ + } while(0) + +/* + * Switch to the next phase of parsing. + */ +#undef NEXT_PHASE +#define NEXT_PHASE(ctx) \ + do { \ + ctx->phase++; \ + ctx->step = 0; \ + } while(0) +#undef SET_PHASE +#define SET_PHASE(ctx, value) \ + do { \ + ctx->phase = value; \ + ctx->step = 0; \ + } while(0) + +/* + * Return a standardized complex structure. + */ +#undef RETURN +#define RETURN(_code) \ + do { \ + asn_dec_rval_t rval; \ + rval.code = _code; \ + rval.consumed = consumed_myself; \ + return rval; \ + } while(0) + +/* + * The SEQUENCE OF and SET OF values utilize a "quantity field". + * It is is a pointless combination of #8.6 (length determinant, capable + * of encoding tiny and huge numbers in the shortest possible number of octets) + * and the variable sized integer. What could have been encoded by #8.6 alone + * is required to be encoded by #8.6 followed by that number of unsigned octets. + * This doesn't make too much sense. It seems that the original version of OER + * standard have been using the unconstrained unsigned integer as a quantity + * field, and this legacy have gone through ISO/ITU-T standardization process. + */ +static ssize_t +oer_fetch_quantity(const void *ptr, size_t size, size_t *qty_r) { + const uint8_t *b; + const uint8_t *bend; + size_t len = 0; + size_t qty; + + ssize_t len_len = oer_fetch_length(ptr, size, &len); + if(len_len <= 0) { + *qty_r = 0; + return len_len; + } + + if((len_len + len) > size) { + *qty_r = 0; + return 0; + } + + b = (const uint8_t *)ptr + len_len; + bend = b + len; + + /* Skip the leading 0-bytes */ + for(; b < bend && *b == 0; b++) { + } + + if((bend - b) > (ssize_t)sizeof(size_t)) { + /* Length is not representable by the native size_t type */ + *qty_r = 0; + return -1; + } + + for(qty = 0; b < bend; b++) { + qty = (qty << 8) + *b; + } + + if(qty > RSIZE_MAX) { /* A bit of C11 validation */ + *qty_r = 0; + return -1; + } + + *qty_r = qty; + assert((size_t)len_len + len == (size_t)(bend - (const uint8_t *)ptr)); + return len_len + len; +} + +asn_dec_rval_t +SET_OF_decode_oer(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, + const asn_oer_constraints_t *constraints, void **struct_ptr, + const void *ptr, size_t size) { + const asn_SET_OF_specifics_t *specs = (const asn_SET_OF_specifics_t *)td->specifics; + asn_dec_rval_t rval = {RC_OK, 0}; + void *st = *struct_ptr; /* Target structure */ + asn_struct_ctx_t *ctx; /* Decoder context */ + size_t consumed_myself = 0; /* Consumed bytes from ptr. */ + + (void)constraints; + + if(ASN__STACK_OVERFLOW_CHECK(opt_codec_ctx)) + ASN__DECODE_FAILED; + + /* + * Create the target structure if it is not present already. + */ + if(st == 0) { + st = *struct_ptr = CALLOC(1, specs->struct_size); + if(st == 0) { + RETURN(RC_FAIL); + } + } + + /* + * Restore parsing context. + */ + ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); + + /* + * Start to parse where left previously. + */ + switch(ctx->phase) { + case 0: { + /* + * Fetch number of elements to decode. + */ + size_t length = 0; + size_t len_size = oer_fetch_quantity(ptr, size, &length); + switch(len_size) { + case 0: + RETURN(RC_WMORE); + case -1: + RETURN(RC_FAIL); + default: + ADVANCE(len_size); + ctx->left = length; + } + } + NEXT_PHASE(ctx); + /* FALL THROUGH */ + case 1: { + /* Decode components of the extension root */ + asn_TYPE_member_t *elm = td->elements; + asn_anonymous_set_ *list = _A_SET_FROM_VOID(st); + const void *base_ptr = ptr; + ber_tlv_len_t base_ctx_left = ctx->left; + + assert(td->elements_count == 1); + + ASN_DEBUG("OER SET OF %s Decoding PHASE 1", td->name); + + for(; ctx->left > 0; ctx->left--) { + asn_dec_rval_t rv = elm->type->op->oer_decoder( + opt_codec_ctx, elm->type, + elm->encoding_constraints.oer_constraints, &ctx->ptr, ptr, + size); + ADVANCE(rv.consumed); + switch(rv.code) { + case RC_OK: + if(ASN_SET_ADD(list, ctx->ptr) != 0) { + RETURN(RC_FAIL); + } else { + ctx->ptr = 0; + /* + * This check is to avoid compression bomb with + * specs like SEQUENCE/SET OF NULL which don't + * consume data at all. + */ + if(rv.consumed == 0 && base_ptr == ptr + && (base_ctx_left - ctx->left) > 200) { + ASN__DECODE_FAILED; + } + break; + } + case RC_WMORE: + RETURN(RC_WMORE); + case RC_FAIL: + ASN_STRUCT_FREE(*elm->type, ctx->ptr); + ctx->ptr = 0; + SET_PHASE(ctx, 3); + RETURN(RC_FAIL); + } + } + /* Decoded decently. */ + NEXT_PHASE(ctx); + } + /* Fall through */ + case 2: + /* Ignore fully decoded */ + assert(ctx->left == 0); + RETURN(RC_OK); + case 3: + /* Failed to decode. */ + RETURN(RC_FAIL); + } + + return rval; +} + +static ssize_t +oer_put_quantity(size_t qty, asn_app_consume_bytes_f *cb, void *app_key) { + uint8_t buf[1 + sizeof(size_t)]; + uint8_t *b = &buf[sizeof(size_t)]; /* Last addressable */ + size_t encoded; + + do { + *b-- = qty; + qty >>= 8; + } while(qty); + + *b = sizeof(buf) - (b-buf) - 1; + encoded = sizeof(buf) - (b-buf); + if(cb(b, encoded, app_key) < 0) + return -1; + return encoded; +} + +/* + * Encode as Canonical OER. + */ +asn_enc_rval_t +SET_OF_encode_oer(const asn_TYPE_descriptor_t *td, + const asn_oer_constraints_t *constraints, const void *sptr, + asn_app_consume_bytes_f *cb, void *app_key) { + const asn_TYPE_member_t *elm; + const asn_anonymous_set_ *list; + size_t computed_size = 0; + ssize_t qty_len; + int n; + + (void)constraints; + + if(!sptr) ASN__ENCODE_FAILED; + + elm = td->elements; + list = _A_CSET_FROM_VOID(sptr); + + qty_len = oer_put_quantity(list->count, cb, app_key); + if(qty_len < 0) { + ASN__ENCODE_FAILED; + } + computed_size += qty_len; + + for(n = 0; n < list->count; n++) { + void *memb_ptr = list->array[n]; + asn_enc_rval_t er; + er = elm->type->op->oer_encoder( + elm->type, elm->encoding_constraints.oer_constraints, memb_ptr, cb, + app_key); + if(er.encoded < 0) { + return er; + } else { + computed_size += er.encoded; + } + } + + { + asn_enc_rval_t erval; + erval.encoded = computed_size; + ASN__ENCODED_OK(erval); + } +} + +#endif /* ASN_DISABLE_OER_SUPPORT */ diff --git a/Vendor/asn1/include/constr_TYPE.c b/Vendor/asn1/include/constr_TYPE.c new file mode 100644 index 0000000..aefaefd --- /dev/null +++ b/Vendor/asn1/include/constr_TYPE.c @@ -0,0 +1,80 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include + +/* + * Version of the ASN.1 infrastructure shipped with compiler. + */ +int get_asn1c_environment_version() { return ASN1C_ENVIRONMENT_VERSION; } + +static asn_app_consume_bytes_f _print2fp; + +/* + * Return the outmost tag of the type. + */ +ber_tlv_tag_t +asn_TYPE_outmost_tag(const asn_TYPE_descriptor_t *type_descriptor, + const void *struct_ptr, int tag_mode, ber_tlv_tag_t tag) { + + if(tag_mode) + return tag; + + if(type_descriptor->tags_count) + return type_descriptor->tags[0]; + + return type_descriptor->op->outmost_tag(type_descriptor, struct_ptr, 0, 0); +} + +/* + * Print the target language's structure in human readable form. + */ +int +asn_fprint(FILE *stream, const asn_TYPE_descriptor_t *td, + const void *struct_ptr) { + if(!stream) stream = stdout; + if(!td || !struct_ptr) { + errno = EINVAL; + return -1; + } + + /* Invoke type-specific printer */ + if(td->op->print_struct(td, struct_ptr, 1, _print2fp, stream)) { + return -1; + } + + /* Terminate the output */ + if(_print2fp("\n", 1, stream)) { + return -1; + } + + return fflush(stream); +} + +/* Dump the data into the specified stdio stream */ +static int +_print2fp(const void *buffer, size_t size, void *app_key) { + FILE *stream = (FILE *)app_key; + + if(fwrite(buffer, 1, size, stream) != size) + return -1; + + return 0; +} + + +/* + * Some compilers do not support variable args macros. + * This function is a replacement of ASN_DEBUG() macro. + */ +void ASN_DEBUG_f(const char *fmt, ...); +void ASN_DEBUG_f(const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); +} diff --git a/Vendor/asn1/include/constr_TYPE.h b/Vendor/asn1/include/constr_TYPE.h new file mode 100644 index 0000000..31102f5 --- /dev/null +++ b/Vendor/asn1/include/constr_TYPE.h @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2003-2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +/* + * This file contains the declaration structure called "ASN.1 Type Definition", + * which holds all information necessary for encoding and decoding routines. + * This structure even contains pointer to these encoding and decoding routines + * for each defined ASN.1 type. + */ +#ifndef _CONSTR_TYPE_H_ +#define _CONSTR_TYPE_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct asn_TYPE_descriptor_s; /* Forward declaration */ +struct asn_TYPE_member_s; /* Forward declaration */ + +/* + * This type provides the context information for various ASN.1 routines, + * primarily ones doing decoding. A member _asn_ctx of this type must be + * included into certain target language's structures, such as compound types. + */ +typedef struct asn_struct_ctx_s { + short phase; /* Decoding phase */ + short step; /* Elementary step of a phase */ + int context; /* Other context information */ + void *ptr; /* Decoder-specific stuff (stack elements) */ + ber_tlv_len_t left; /* Number of bytes left, -1 for indefinite */ +} asn_struct_ctx_t; + +#include /* Basic Encoding Rules decoder */ +#include /* Distinguished Encoding Rules encoder */ +#include /* Decoder of XER (XML, text) */ +#include /* Encoder into XER (XML, text) */ +#include /* Packet Encoding Rules decoder */ +#include /* Packet Encoding Rules encoder */ +#include /* Subtype constraints support */ +#include /* Random structures support */ + +#ifdef ASN_DISABLE_OER_SUPPORT +typedef void (oer_type_decoder_f)(); +typedef void (oer_type_encoder_f)(); +typedef void asn_oer_constraints_t; +#else +#include /* Octet Encoding Rules encoder */ +#include /* Octet Encoding Rules encoder */ +#endif + +/* + * Free the structure according to its specification. + * Use one of ASN_STRUCT_{FREE,RESET,CONTENTS_ONLY} macros instead. + * Do not use directly. + */ +enum asn_struct_free_method { + ASFM_FREE_EVERYTHING, /* free(struct_ptr) and underlying members */ + ASFM_FREE_UNDERLYING, /* free underlying members */ + ASFM_FREE_UNDERLYING_AND_RESET /* FREE_UNDERLYING + memset(0) */ +}; +typedef void (asn_struct_free_f)( + const struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, enum asn_struct_free_method); + +/* + * Free the structure including freeing the memory pointed to by ptr itself. + */ +#define ASN_STRUCT_FREE(asn_DEF, ptr) \ + (asn_DEF).op->free_struct(&(asn_DEF), (ptr), ASFM_FREE_EVERYTHING) + +/* + * Free the memory used by the members of the structure without freeing the + * the structure pointer itself. + * ZERO-OUT the structure to the safe clean state. + * (Retaining the pointer may be useful in case the structure is allocated + * statically or arranged on the stack, yet its elements are dynamic.) + */ +#define ASN_STRUCT_RESET(asn_DEF, ptr) \ + (asn_DEF).op->free_struct(&(asn_DEF), (ptr), ASFM_FREE_UNDERLYING_AND_RESET) + +/* + * Free memory used by the members of the structure without freeing + * the structure pointer itself. + * (Retaining the pointer may be useful in case the structure is allocated + * statically or arranged on the stack, yet its elements are dynamic.) + * AVOID using it in the application code; + * Use a safer ASN_STRUCT_RESET() instead. + */ +#define ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF, ptr) \ + (asn_DEF).op->free_struct(&(asn_DEF), (ptr), ASFM_FREE_UNDERLYING) + +/* + * Print the structure according to its specification. + */ +typedef int(asn_struct_print_f)( + const struct asn_TYPE_descriptor_s *type_descriptor, + const void *struct_ptr, + int level, /* Indentation level */ + asn_app_consume_bytes_f *callback, void *app_key); + +/* + * Compare two structs between each other. + * Returns <0 if struct_A is "smaller" than struct_B, >0 if "greater", + * and =0 if "equal to", for some type-specific, stable definition of + * "smaller", "greater" and "equal to". + */ +typedef int (asn_struct_compare_f)( + const struct asn_TYPE_descriptor_s *type_descriptor, + const void *struct_A, + const void *struct_B); + +/* + * Return the outmost tag of the type. + * If the type is untagged CHOICE, the dynamic operation is performed. + * NOTE: This function pointer type is only useful internally. + * Do not use it in your application. + */ +typedef ber_tlv_tag_t (asn_outmost_tag_f)( + const struct asn_TYPE_descriptor_s *type_descriptor, + const void *struct_ptr, int tag_mode, ber_tlv_tag_t tag); +/* The instance of the above function type; used internally. */ +asn_outmost_tag_f asn_TYPE_outmost_tag; + +/* + * Fetch the desired type of the Open Type based on the + * Information Object Set driven constraints. + */ +typedef struct asn_type_selector_result_s { + const struct asn_TYPE_descriptor_s *type_descriptor; /* Type encoded. */ + unsigned presence_index; /* Associated choice variant. */ +} asn_type_selector_result_t; +typedef asn_type_selector_result_t(asn_type_selector_f)( + const struct asn_TYPE_descriptor_s *parent_type_descriptor, + const void *parent_structure_ptr); + +/* + * Generalized functions for dealing with the speciic type. + * May be directly invoked by applications. + */ +typedef struct asn_TYPE_operation_s { + asn_struct_free_f *free_struct; /* Free the structure */ + asn_struct_print_f *print_struct; /* Human readable output */ + asn_struct_compare_f *compare_struct; /* Compare two structures */ + ber_type_decoder_f *ber_decoder; /* Generic BER decoder */ + der_type_encoder_f *der_encoder; /* Canonical DER encoder */ + xer_type_decoder_f *xer_decoder; /* Generic XER decoder */ + xer_type_encoder_f *xer_encoder; /* [Canonical] XER encoder */ + oer_type_decoder_f *oer_decoder; /* Generic OER decoder */ + oer_type_encoder_f *oer_encoder; /* Canonical OER encoder */ + per_type_decoder_f *uper_decoder; /* Unaligned PER decoder */ + per_type_encoder_f *uper_encoder; /* Unaligned PER encoder */ + asn_random_fill_f *random_fill; /* Initialize with a random value */ + asn_outmost_tag_f *outmost_tag; /* */ +} asn_TYPE_operation_t; + +/* + * A constraints tuple specifying both the OER and PER constraints. + */ +typedef struct asn_encoding_constraints_s { + const struct asn_oer_constraints_s *oer_constraints; + const struct asn_per_constraints_s *per_constraints; + asn_constr_check_f *general_constraints; +} asn_encoding_constraints_t; + +/* + * The definitive description of the destination language's structure. + */ +typedef struct asn_TYPE_descriptor_s { + const char *name; /* A name of the ASN.1 type. "" in some cases. */ + const char *xml_tag; /* Name used in XML tag */ + + /* + * Generalized functions for dealing with the specific type. + * May be directly invoked by applications. + */ + asn_TYPE_operation_t *op; + + /*********************************************************************** + * Internally useful members. Not to be used by applications directly. * + **********************************************************************/ + + /* + * Tags that are expected to occur. + */ + const ber_tlv_tag_t *tags; /* Effective tags sequence for this type */ + unsigned tags_count; /* Number of tags which are expected */ + const ber_tlv_tag_t *all_tags; /* Every tag for BER/containment */ + unsigned all_tags_count; /* Number of tags */ + + /* OER, PER, and general constraints */ + asn_encoding_constraints_t encoding_constraints; + + /* + * An ASN.1 production type members (members of SEQUENCE, SET, CHOICE). + */ + struct asn_TYPE_member_s *elements; + unsigned elements_count; + + /* + * Additional information describing the type, used by appropriate + * functions above. + */ + const void *specifics; +} asn_TYPE_descriptor_t; + +/* + * This type describes an element of the constructed type, + * i.e. SEQUENCE, SET, CHOICE, etc. + */ + enum asn_TYPE_flags_e { + ATF_NOFLAGS, + ATF_POINTER = 0x01, /* Represented by the pointer */ + ATF_OPEN_TYPE = 0x02, /* Open Type */ + ATF_ANY_TYPE = 0x04 /* ANY type (deprecated!) */ + }; +typedef struct asn_TYPE_member_s { + enum asn_TYPE_flags_e flags; /* Element's presentation flags */ + unsigned optional; /* Following optional members, including current */ + unsigned memb_offset; /* Offset of the element */ + ber_tlv_tag_t tag; /* Outmost (most immediate) tag */ + int tag_mode; /* IMPLICIT/no/EXPLICIT tag at current level */ + asn_TYPE_descriptor_t *type; /* Member type descriptor */ + asn_type_selector_f *type_selector; /* IoS runtime type selector */ + asn_encoding_constraints_t encoding_constraints; + int (*default_value_cmp)(const void *sptr); /* Compare DEFAULT */ + int (*default_value_set)(void **sptr); /* Set DEFAULT */ + const char *name; /* ASN.1 identifier of the element */ +} asn_TYPE_member_t; + +/* + * BER tag to element number mapping. + */ +typedef struct asn_TYPE_tag2member_s { + ber_tlv_tag_t el_tag; /* Outmost tag of the member */ + unsigned el_no; /* Index of the associated member, base 0 */ + int toff_first; /* First occurence of the el_tag, relative */ + int toff_last; /* Last occurence of the el_tag, relative */ +} asn_TYPE_tag2member_t; + +/* + * This function prints out the contents of the target language's structure + * (struct_ptr) into the file pointer (stream) in human readable form. + * RETURN VALUES: + * 0: The structure is printed. + * -1: Problem dumping the structure. + * (See also xer_fprint() in xer_encoder.h) + */ +int asn_fprint(FILE *stream, /* Destination stream descriptor */ + const asn_TYPE_descriptor_t *td, /* ASN.1 type descriptor */ + const void *struct_ptr); /* Structure to be printed */ + +#ifdef __cplusplus +} +#endif + +#endif /* _CONSTR_TYPE_H_ */ diff --git a/Vendor/asn1/include/constraints.c b/Vendor/asn1/include/constraints.c new file mode 100644 index 0000000..df3c6c1 --- /dev/null +++ b/Vendor/asn1/include/constraints.c @@ -0,0 +1,93 @@ +#include +#include + +int +asn_generic_no_constraint(const asn_TYPE_descriptor_t *type_descriptor, + const void *struct_ptr, + asn_app_constraint_failed_f *cb, void *key) { + (void)type_descriptor; /* Unused argument */ + (void)struct_ptr; /* Unused argument */ + (void)cb; /* Unused argument */ + (void)key; /* Unused argument */ + + /* Nothing to check */ + return 0; +} + +int +asn_generic_unknown_constraint(const asn_TYPE_descriptor_t *type_descriptor, + const void *struct_ptr, + asn_app_constraint_failed_f *cb, void *key) { + (void)type_descriptor; /* Unused argument */ + (void)struct_ptr; /* Unused argument */ + (void)cb; /* Unused argument */ + (void)key; /* Unused argument */ + + /* Unknown how to check */ + return 0; +} + +struct errbufDesc { + const asn_TYPE_descriptor_t *failed_type; + const void *failed_struct_ptr; + char *errbuf; + size_t errlen; +}; + +static void +_asn_i_ctfailcb(void *key, const asn_TYPE_descriptor_t *td, const void *sptr, + const char *fmt, ...) { + struct errbufDesc *arg = key; + va_list ap; + ssize_t vlen; + ssize_t maxlen; + + arg->failed_type = td; + arg->failed_struct_ptr = sptr; + + maxlen = arg->errlen; + if(maxlen <= 0) + return; + + va_start(ap, fmt); + vlen = vsnprintf(arg->errbuf, maxlen, fmt, ap); + va_end(ap); + if(vlen >= maxlen) { + arg->errbuf[maxlen-1] = '\0'; /* Ensuring libc correctness */ + arg->errlen = maxlen - 1; /* Not counting termination */ + return; + } else if(vlen >= 0) { + arg->errbuf[vlen] = '\0'; /* Ensuring libc correctness */ + arg->errlen = vlen; /* Not counting termination */ + } else { + /* + * The libc on this system is broken. + */ + vlen = sizeof("") - 1; + maxlen--; + arg->errlen = vlen < maxlen ? vlen : maxlen; + memcpy(arg->errbuf, "", arg->errlen); + arg->errbuf[arg->errlen] = 0; + } + + return; +} + +int +asn_check_constraints(const asn_TYPE_descriptor_t *type_descriptor, + const void *struct_ptr, char *errbuf, size_t *errlen) { + struct errbufDesc arg; + int ret; + + arg.failed_type = 0; + arg.failed_struct_ptr = 0; + arg.errbuf = errbuf; + arg.errlen = errlen ? *errlen : 0; + + ret = type_descriptor->encoding_constraints.general_constraints( + type_descriptor, struct_ptr, _asn_i_ctfailcb, &arg); + if(ret == -1 && errlen) *errlen = arg.errlen; + + return ret; +} + diff --git a/Vendor/asn1/include/constraints.h b/Vendor/asn1/include/constraints.h new file mode 100644 index 0000000..0bd86a9 --- /dev/null +++ b/Vendor/asn1/include/constraints.h @@ -0,0 +1,62 @@ +/*- + * Copyright (c) 2004-2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef ASN1_CONSTRAINTS_VALIDATOR_H +#define ASN1_CONSTRAINTS_VALIDATOR_H + +#include /* Platform-dependent types */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct asn_TYPE_descriptor_s; /* Forward declaration */ + +/* + * Validate the structure according to the ASN.1 constraints. + * If errbuf and errlen are given, they shall be pointing to the appropriate + * buffer space and its length before calling this function. Alternatively, + * they could be passed as NULL's. If constraints validation fails, + * errlen will contain the actual number of bytes taken from the errbuf + * to encode an error message (properly 0-terminated). + * + * RETURN VALUES: + * This function returns 0 in case all ASN.1 constraints are met + * and -1 if one or more constraints were failed. + */ +int asn_check_constraints( + const struct asn_TYPE_descriptor_s *type_descriptor, + const void *struct_ptr, /* Target language's structure */ + char *errbuf, /* Returned error description */ + size_t *errlen /* Length of the error description */ +); + + +/* + * Generic type for constraint checking callback, + * associated with every type descriptor. + */ +typedef int(asn_constr_check_f)( + const struct asn_TYPE_descriptor_s *type_descriptor, const void *struct_ptr, + asn_app_constraint_failed_f *optional_callback, /* Log the error */ + void *optional_app_key /* Opaque key passed to a callback */ +); + +/******************************* + * INTERNALLY USEFUL FUNCTIONS * + *******************************/ + +asn_constr_check_f asn_generic_no_constraint; /* No constraint whatsoever */ +asn_constr_check_f asn_generic_unknown_constraint; /* Not fully supported */ + +/* + * Invoke the callback with a complete error message. + */ +#define ASN__CTFAIL if(ctfailcb) ctfailcb + +#ifdef __cplusplus +} +#endif + +#endif /* ASN1_CONSTRAINTS_VALIDATOR_H */ diff --git a/Vendor/asn1/include/converter-example.c b/Vendor/asn1/include/converter-example.c new file mode 100644 index 0000000..b540452 --- /dev/null +++ b/Vendor/asn1/include/converter-example.c @@ -0,0 +1,1020 @@ +/* + * Generic converter template for a selected ASN.1 type. + * Copyright (c) 2005-2017 Lev Walkin . + * All rights reserved. + * + * To compile with your own ASN.1 type, redefine the PDU as shown: + * + * cc -DPDU=MyCustomType -o myDecoder.o -c converter-example.c + */ +#ifdef HAVE_CONFIG_H +#include +#endif +#define __EXTENSIONS__ +#include +#include +#include /* for atoi(3) */ +#include /* for getopt(3) */ +#include /* for strerror(3) */ +#include /* for EX_* exit codes */ +#include /* for errno */ +#include /* for isatty(3) */ +#include +#include /* for ASN__DEFAULT_STACK_MAX */ + +/* Convert "Type" defined by -DPDU into "asn_DEF_Type" */ +#ifdef PDU +#define ASN_DEF_PDU(t) asn_DEF_ ## t +#define DEF_PDU_Type(t) ASN_DEF_PDU(t) +#define PDU_Type DEF_PDU_Type(PDU) +extern asn_TYPE_descriptor_t PDU_Type; /* ASN.1 type to be decoded */ +#define PDU_Type_Ptr (&PDU_Type) +#else /* !PDU */ +#define PDU_Type_Ptr NULL +#endif /* PDU */ + +#ifdef ASN_PDU_COLLECTION /* Generated by asn1c -pdu=... */ +extern asn_TYPE_descriptor_t *asn_pdu_collection[]; +#endif + +#ifndef NO_ASN_PDU +#if !defined(PDU) && !defined(ASN_PDU_COLLECTION) +#error Define -DPDU to compile this example converter. +#error `asn1c -pdu=...` adds necessary flags automatically. +#endif +#endif + +/* + * Open file and parse its contens. + */ +static void *data_decode_from_file(enum asn_transfer_syntax, + asn_TYPE_descriptor_t *asnTypeOfPDU, + FILE *file, const char *name, + ssize_t suggested_bufsize, int first_pdu); +static int write_out(const void *buffer, size_t size, void *key); +static FILE *argument_to_file(char *av[], int idx); +static char *argument_to_name(char *av[], int idx); + + int opt_debug; /* -d (or -dd) */ +static int opt_check; /* -c (constraints checking) */ +static int opt_stack; /* -s (maximum stack size) */ +static int opt_nopad; /* -per-nopad (PER input is not padded between msgs) */ +static int opt_onepdu; /* -1 (decode single PDU) */ + +#ifdef JUNKTEST /* Enable -J */ +#define JUNKOPT "J:" +static double opt_jprob; /* Junk bit probability */ +static int junk_failures; +static void junk_bytes_with_probability(uint8_t *, size_t, double prob); + +#define RANDOPT "R:" +static ssize_t random_max_size = 0; /* Size of the random data */ + +#if !defined(__FreeBSD__) && !(defined(__APPLE__) && defined(__MACH__)) +static void +srandomdev(void) { + FILE *f = fopen("/dev/urandom", "rb"); + unsigned seed; + if(f) { + if(fread(&seed, 1, sizeof(seed), f) != sizeof(seed)) { + seed = time(NULL); + } + fclose(f); + } else { + seed = time(NULL); + } + srandom(seed); +} +#endif + +#else /* !JUNKTEST */ +#define JUNKOPT +#define RANDOPT +#endif /* JUNKTEST */ + +/* Debug output function */ +static void CC_PRINTFLIKE(1, 2) +DEBUG(const char *fmt, ...) { + va_list ap; + if(!opt_debug) return; + fprintf(stderr, "AD: "); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, "\n"); +} + +static const char * +ats_simple_name(enum asn_transfer_syntax syntax) { + switch(syntax) { + case ATS_INVALID: + return "/dev/null"; + case ATS_NONSTANDARD_PLAINTEXT: + return "plaintext"; + case ATS_BER: + return "BER"; + case ATS_DER: + return "DER"; + case ATS_CER: + return "CER"; + case ATS_BASIC_OER: + case ATS_CANONICAL_OER: + return "OER"; + case ATS_BASIC_XER: + case ATS_CANONICAL_XER: + return "XER"; + case ATS_UNALIGNED_BASIC_PER: + case ATS_UNALIGNED_CANONICAL_PER: + return "PER"; + default: + return ""; + } +} + +#define CODEC_OFFSET(fname) ((ptrdiff_t)&(((asn_TYPE_operation_t *)0)->fname)) +typedef struct { + const char *name; + enum asn_transfer_syntax syntax; + ptrdiff_t codec_offset; + const char *full_name; +} syntax_selector; + +static syntax_selector input_encodings[] = { + {"ber", ATS_BER, CODEC_OFFSET(ber_decoder), + "Input is in BER (Basic Encoding Rules) or DER"}, + {"oer", ATS_BASIC_OER, CODEC_OFFSET(oer_decoder), + "Input is in OER (Octet Encoding Rules)"}, + {"per", ATS_UNALIGNED_BASIC_PER, CODEC_OFFSET(uper_decoder), + "Input is in Unaligned PER (Packed Encoding Rules)"}, + {"xer", ATS_BASIC_XER, CODEC_OFFSET(xer_decoder), + "Input is in XER (XML Encoding Rules)"}, + {0, ATS_INVALID, 0, 0}}; + +static syntax_selector output_encodings[] = { + {"der", ATS_DER, CODEC_OFFSET(der_encoder), + "Output as DER (Distinguished Encoding Rules)"}, + {"oer", ATS_CANONICAL_OER, CODEC_OFFSET(oer_encoder), + "Output as Canonical OER (Octet Encoding Rules)"}, + {"per", ATS_UNALIGNED_CANONICAL_PER, CODEC_OFFSET(uper_encoder), + "Output as Unaligned PER (Packed Encoding Rules)"}, + {"xer", ATS_BASIC_XER, CODEC_OFFSET(xer_encoder), + "Output as XER (XML Encoding Rules)"}, + {"text", ATS_NONSTANDARD_PLAINTEXT, CODEC_OFFSET(print_struct), + "Output as plain semi-structured text"}, + {"null", ATS_INVALID, CODEC_OFFSET(print_struct), + "Verify (decode) input, but do not output"}, + {0, ATS_INVALID, 0, 0}}; + +static int +has_codec_defined(const asn_TYPE_descriptor_t *td, + const syntax_selector *element) { + return *(const void *const *)(const void *)((const char *)td->op + + element->codec_offset) != 0; +} + +/* + * Select ASN.1 Transfer Enocoding Syntax by command line name. + */ +static const syntax_selector * +ats_by_name(const char *name, const asn_TYPE_descriptor_t *td, + const syntax_selector *first_element) { + const syntax_selector *element; + for(element = first_element; element->name; element++) { + if(strcmp(element->name, name) == 0) { + if(td && td->op && has_codec_defined(td, element)) { + return element; + } + } + } + return NULL; +} + +int +main(int ac, char *av[]) { + FILE *binary_out; + asn_TYPE_descriptor_t *pduType = PDU_Type_Ptr; + asn_TYPE_descriptor_t *anyPduType = PDU_Type_Ptr; + ssize_t suggested_bufsize = 8192; /* close or equal to stdio buffer */ + int number_of_iterations = 1; + int num; + int ch; + const syntax_selector *sel; + enum asn_transfer_syntax isyntax = ATS_INVALID; + enum asn_transfer_syntax osyntax = ATS_BASIC_XER; + + if(!anyPduType) { +#ifdef ASN_PDU_COLLECTION + anyPduType = asn_pdu_collection[0]; + if(!anyPduType) { + fprintf(stderr, + "Empty PDU collection, no reference PDU to choose from.\n"); + exit(EX_SOFTWARE); + } +#else + fprintf(stderr, "Either asn1c -pdu=... or cc -DPDU should be used.\n"); + exit(EX_SOFTWARE); +#endif + } + + /* Figure out if a specialty decoder needs to be default */ +#ifndef ASN_DISABLE_OER_SUPPORT + isyntax = ATS_BASIC_OER; +#endif +#ifndef ASN_DISABLE_PER_SUPPORT + isyntax = ATS_UNALIGNED_BASIC_PER; +#endif + + /* + * Pocess the command-line argments. + */ + while((ch = getopt(ac, av, "i:o:1b:cdn:p:hs:" JUNKOPT RANDOPT)) != -1) + switch(ch) { + case 'i': + sel = ats_by_name(optarg, anyPduType, input_encodings); + if(sel) { + isyntax = sel->syntax; + } else { + fprintf(stderr, "-i: '%s': improper format selector\n", + optarg); + exit(EX_UNAVAILABLE); + } + break; + case 'o': + sel = ats_by_name(optarg, anyPduType, output_encodings); + if(sel) { + osyntax = sel->syntax; + } else { + fprintf(stderr, "-o: '%s': improper format selector\n", + optarg); + exit(EX_UNAVAILABLE); + } + break; + case '1': + opt_onepdu = 1; + break; + case 'b': + suggested_bufsize = atoi(optarg); + if(suggested_bufsize < 1 + || suggested_bufsize > 16 * 1024 * 1024) { + fprintf(stderr, + "-b %s: Improper buffer size (1..16M)\n", + optarg); + exit(EX_UNAVAILABLE); + } + break; + case 'c': + opt_check = 1; + break; + case 'd': + opt_debug++; /* Double -dd means ASN.1 debug */ + break; + case 'n': + number_of_iterations = atoi(optarg); + if(number_of_iterations < 1) { + fprintf(stderr, + "-n %s: Improper iterations count\n", optarg); + exit(EX_UNAVAILABLE); + } + break; + case 'p': + if(strcmp(optarg, "er-nopad") == 0) { + opt_nopad = 1; + break; + } +#ifdef ASN_PDU_COLLECTION + if(strcmp(optarg, "list") == 0) { + asn_TYPE_descriptor_t **pdu = asn_pdu_collection; + fprintf(stderr, "Available PDU types:\n"); + for(; *pdu; pdu++) printf("%s\n", (*pdu)->name); + exit(0); + } else if(optarg[0] >= 'A' && optarg[0] <= 'Z') { + asn_TYPE_descriptor_t **pdu = asn_pdu_collection; + while(*pdu && strcmp((*pdu)->name, optarg)) pdu++; + if(*pdu) { pduType = *pdu; break; } + fprintf(stderr, "-p %s: Unrecognized PDU. Try '-p list'.\n", + optarg); + exit(EX_USAGE); + } +#else /* Without -pdu=auto there's just a single type */ + if(strcmp(optarg, "list") == 0) { + fprintf(stderr, "Available PDU types:\n"); + if(pduType) { + printf("%s\n", pduType->name); + } + exit(0); + } else if(optarg[0] >= 'A' && optarg[0] <= 'Z') { + if(pduType && strcmp(optarg, pduType->name) == 0) { + break; + } + fprintf(stderr, "-p %s: Unrecognized PDU. Try '-p list'.\n", + optarg); + exit(EX_USAGE); + } +#endif /* ASN_PDU_COLLECTION */ + fprintf(stderr, "-p %s: Unrecognized option\n", optarg); + exit(EX_UNAVAILABLE); + case 's': + opt_stack = atoi(optarg); + if(opt_stack < 0) { + fprintf(stderr, + "-s %s: Non-negative value expected\n", + optarg); + exit(EX_UNAVAILABLE); + } + break; +#ifdef JUNKTEST + case 'J': + opt_jprob = strtod(optarg, 0); + if(opt_jprob <= 0.0 || opt_jprob > 1.0) { + fprintf(stderr, + "-J %s: Probability range 0..1 expected \n", + optarg); + exit(EX_UNAVAILABLE); + } + break; + case 'R': + isyntax = ATS_RANDOM; + random_max_size = atoi(optarg); + if(random_max_size < 0) { + fprintf(stderr, + "-R %s: Non-negative value expected\n", + optarg); + exit(EX_UNAVAILABLE); + } + srandomdev(); + break; +#endif /* JUNKTEST */ + case 'h': + default: +#ifdef ASN_CONVERTER_TITLE +#define _AXS(x) #x +#define _ASX(x) _AXS(x) + fprintf(stderr, "%s\n", _ASX(ASN_CONVERTER_TITLE)); +#endif + fprintf(stderr, "Usage: %s [options] ...\n", av[0]); + fprintf(stderr, "Where options are:\n"); + for(sel = input_encodings; sel->name; sel++) { + if(ats_by_name(sel->name, anyPduType, sel)) { + fprintf(stderr, " -i%s %s%s\n", sel->name, + sel->full_name, + (sel->syntax == isyntax) ? " (DEFAULT)" : ""); + } + } + for(sel = output_encodings; sel->name; sel++) { + if(ats_by_name(sel->name, anyPduType, sel)) { + fprintf(stderr, " -o%s%s %s%s\n", sel->name, + strlen(sel->name) > 3 ? "" : " ", + sel->full_name, + (sel->syntax == osyntax) ? " (DEFAULT)" : ""); + } + } + if(anyPduType->op->uper_decoder) { + fprintf(stderr, + " -per-nopad Assume PER PDUs are not padded (-iper)\n"); + } +#ifdef ASN_PDU_COLLECTION + fprintf(stderr, + " -p Specify PDU type to decode\n" + " -p list List available PDUs\n"); +#endif /* ASN_PDU_COLLECTION */ + fprintf(stderr, + " -1 Decode only the first PDU in file\n" + " -b Set the i/o buffer size (default is %ld)\n" + " -c Check ASN.1 constraints after decoding\n" + " -d Enable debugging (-dd is even better)\n" + " -n Process files times\n" + " -s Set the stack usage limit (default is %d)\n" +#ifdef JUNKTEST + " -J Set random junk test bit garbaging probability\n" + " -R Generate a random value of roughly the given size,\n" + " instead of parsing the value from file.\n" +#endif + , (long)suggested_bufsize, ASN__DEFAULT_STACK_MAX); + exit(EX_USAGE); + } + + ac -= optind; + av += optind; + + if(!pduType) { +#ifdef NO_ASN_PDU + fprintf(stderr, "No -DPDU defined during compilation.\n"); + exit(0); +#else + fprintf(stderr, "Use '-p ' or '-p list' to select ASN.1 type.\n"); + exit(EX_USAGE); +#endif /* NO_ASN_PDU */ + } + + if(ac < 1 && isyntax != ATS_RANDOM) { + fprintf(stderr, "%s: No input files specified. " + "Try '-h' for more information\n", + av[-optind]); + exit(EX_USAGE); + } + + if(isatty(1)) { + const int is_text_output = osyntax == ATS_NONSTANDARD_PLAINTEXT + || osyntax == ATS_BASIC_XER + || osyntax == ATS_CANONICAL_XER; + if(is_text_output) { + binary_out = stdout; + } else { + fprintf(stderr, "(Suppressing binary output to a terminal.)\n"); + binary_out = fopen("/dev/null", "wb"); + if(!binary_out) { + fprintf(stderr, "Can't open /dev/null: %s\n", strerror(errno)); + exit(EX_OSERR); + } + } + } else { + binary_out = stdout; + } + setvbuf(stdout, 0, _IOLBF, 0); + + for(num = 0; num < number_of_iterations; num++) { + int ac_i; + /* + * Process all files in turn. + */ + for(ac_i = (isyntax == ATS_RANDOM) ? -1 : 0; ac_i < ac; ac_i++) { + asn_enc_rval_t erv; + void *structure; /* Decoded structure */ + FILE *file; + char *name; + int first_pdu; + + if(ac_i == -1) { + file = NULL; + name = ""; + opt_onepdu = 1; + } else { + file = argument_to_file(av, ac_i); + name = argument_to_name(av, ac_i); + } + + for(first_pdu = 1; (first_pdu || !opt_onepdu); first_pdu = 0) { + /* + * Decode the encoded structure from file. + */ +#ifdef JUNKTEST + if(isyntax == ATS_RANDOM) { + structure = NULL; + if(asn_random_fill(pduType, &structure, random_max_size) != 0) { + fprintf(stderr, "Cannot generate a random value.\n"); + assert(structure == NULL); + errno = EINVAL; + } + } else { +#endif + structure = data_decode_from_file(isyntax, pduType, file, name, + suggested_bufsize, first_pdu); +#ifdef JUNKTEST + } +#endif + if(!structure) { + if(errno) { + /* Error message is already printed */ + exit(EX_DATAERR); + } else { + /* EOF */ + break; + } + } + + /* Check ASN.1 constraints */ + if(opt_check) { + char errbuf[128]; + size_t errlen = sizeof(errbuf); + if(asn_check_constraints(pduType, structure, errbuf, &errlen)) { + fprintf(stderr, + "%s: ASN.1 constraint " + "check failed: %s\n", + name, errbuf); + exit(EX_DATAERR); + } + } + + if(osyntax == ATS_INVALID) { +#ifdef JUNKTEST + if(opt_jprob == 0.0) { + fprintf(stderr, "%s: decoded successfully\n", name); + } +#else + fprintf(stderr, "%s: decoded successfully\n", name); +#endif + } else { + erv = asn_encode(NULL, osyntax, pduType, structure, write_out, + binary_out); + + if(erv.encoded == -1) { + fprintf(stderr, "%s: Cannot convert %s into %s\n", name, + pduType->name, ats_simple_name(osyntax)); + DEBUG("Conversion failed for %s:\n", pduType->name); + asn_fprint(stderr, pduType, structure); + exit(EX_UNAVAILABLE); + } + DEBUG("Encoded in %" ASN_PRI_SSIZE " bytes of %s", erv.encoded, + ats_simple_name(osyntax)); + } + + ASN_STRUCT_FREE(*pduType, structure); + } + + if(file && file != stdin) { + fclose(file); + } + } + } + +#ifdef JUNKTEST + if(opt_jprob > 0.0) { + fprintf(stderr, "Junked %f OK (%d/%d)\n", + opt_jprob, junk_failures, number_of_iterations); + } +#endif /* JUNKTEST */ + + return 0; +} + +static struct dynamic_buffer { + uint8_t *data; /* Pointer to the data bytes */ + size_t offset; /* Offset from the start */ + size_t length; /* Length of meaningful contents */ + size_t unbits; /* Unused bits in the last byte */ + size_t allocated; /* Allocated memory for data */ + int nreallocs; /* Number of data reallocations */ + off_t bytes_shifted; /* Number of bytes ever shifted */ +} DynamicBuffer; + +static void +buffer_dump() { + uint8_t *p = DynamicBuffer.data + DynamicBuffer.offset; + uint8_t *e = p + DynamicBuffer.length - (DynamicBuffer.unbits ? 1 : 0); + if(!opt_debug) return; + DEBUG("Buffer: { d=%p, o=%" ASN_PRI_SIZE ", l=%" ASN_PRI_SIZE + ", u=%" ASN_PRI_SIZE ", a=%" ASN_PRI_SIZE ", s=%" ASN_PRI_SIZE " }", + (const void *)DynamicBuffer.data, + DynamicBuffer.offset, + DynamicBuffer.length, + DynamicBuffer.unbits, + DynamicBuffer.allocated, + (size_t)DynamicBuffer.bytes_shifted); + for(; p < e; p++) { + fprintf(stderr, " %c%c%c%c%c%c%c%c", + ((*p >> 7) & 1) ? '1' : '0', + ((*p >> 6) & 1) ? '1' : '0', + ((*p >> 5) & 1) ? '1' : '0', + ((*p >> 4) & 1) ? '1' : '0', + ((*p >> 3) & 1) ? '1' : '0', + ((*p >> 2) & 1) ? '1' : '0', + ((*p >> 1) & 1) ? '1' : '0', + ((*p >> 0) & 1) ? '1' : '0'); + } + if(DynamicBuffer.unbits) { + unsigned int shift; + fprintf(stderr, " "); + for(shift = 7; shift >= DynamicBuffer.unbits; shift--) + fprintf(stderr, "%c", ((*p >> shift) & 1) ? '1' : '0'); + fprintf(stderr, " %" ASN_PRI_SSIZE ":%" ASN_PRI_SSIZE "\n", + (ssize_t)DynamicBuffer.length - 1, + (ssize_t)8 - DynamicBuffer.unbits); + } else { + fprintf(stderr, " %ld\n", (long)DynamicBuffer.length); + } +} + +/* + * Move the buffer content left N bits, possibly joining it with + * preceeding content. + */ +static void +buffer_shift_left(size_t offset, int bits) { + uint8_t *ptr = DynamicBuffer.data + DynamicBuffer.offset + offset; + uint8_t *end = DynamicBuffer.data + DynamicBuffer.offset + + DynamicBuffer.length - 1; + + if(!bits) return; + + DEBUG("Shifting left %d bits off %ld (o=%ld, u=%ld, l=%ld)", + bits, (long)offset, + (long)DynamicBuffer.offset, + (long)DynamicBuffer.unbits, + (long)DynamicBuffer.length); + + if(offset) { + int right; + right = ptr[0] >> (8 - bits); + + DEBUG("oleft: %c%c%c%c%c%c%c%c", + ((ptr[-1] >> 7) & 1) ? '1' : '0', + ((ptr[-1] >> 6) & 1) ? '1' : '0', + ((ptr[-1] >> 5) & 1) ? '1' : '0', + ((ptr[-1] >> 4) & 1) ? '1' : '0', + ((ptr[-1] >> 3) & 1) ? '1' : '0', + ((ptr[-1] >> 2) & 1) ? '1' : '0', + ((ptr[-1] >> 1) & 1) ? '1' : '0', + ((ptr[-1] >> 0) & 1) ? '1' : '0'); + + DEBUG("oriht: %c%c%c%c%c%c%c%c", + ((ptr[0] >> 7) & 1) ? '1' : '0', + ((ptr[0] >> 6) & 1) ? '1' : '0', + ((ptr[0] >> 5) & 1) ? '1' : '0', + ((ptr[0] >> 4) & 1) ? '1' : '0', + ((ptr[0] >> 3) & 1) ? '1' : '0', + ((ptr[0] >> 2) & 1) ? '1' : '0', + ((ptr[0] >> 1) & 1) ? '1' : '0', + ((ptr[0] >> 0) & 1) ? '1' : '0'); + + DEBUG("mriht: %c%c%c%c%c%c%c%c", + ((right >> 7) & 1) ? '1' : '0', + ((right >> 6) & 1) ? '1' : '0', + ((right >> 5) & 1) ? '1' : '0', + ((right >> 4) & 1) ? '1' : '0', + ((right >> 3) & 1) ? '1' : '0', + ((right >> 2) & 1) ? '1' : '0', + ((right >> 1) & 1) ? '1' : '0', + ((right >> 0) & 1) ? '1' : '0'); + + ptr[-1] = (ptr[-1] & (0xff << bits)) | right; + + DEBUG("after: %c%c%c%c%c%c%c%c", + ((ptr[-1] >> 7) & 1) ? '1' : '0', + ((ptr[-1] >> 6) & 1) ? '1' : '0', + ((ptr[-1] >> 5) & 1) ? '1' : '0', + ((ptr[-1] >> 4) & 1) ? '1' : '0', + ((ptr[-1] >> 3) & 1) ? '1' : '0', + ((ptr[-1] >> 2) & 1) ? '1' : '0', + ((ptr[-1] >> 1) & 1) ? '1' : '0', + ((ptr[-1] >> 0) & 1) ? '1' : '0'); + } + + buffer_dump(); + + for(; ptr < end; ptr++) { + int right = ptr[1] >> (8 - bits); + *ptr = (*ptr << bits) | right; + } + *ptr <<= bits; + + DEBUG("Unbits [%" ASN_PRI_SIZE "=>", DynamicBuffer.unbits); + if(DynamicBuffer.unbits == 0) { + DynamicBuffer.unbits += bits; + } else { + DynamicBuffer.unbits += bits; + if(DynamicBuffer.unbits > 7) { + DynamicBuffer.unbits -= 8; + DynamicBuffer.length--; + DynamicBuffer.bytes_shifted++; + } + } + DEBUG("Unbits =>%" ASN_PRI_SIZE "]", DynamicBuffer.unbits); + + buffer_dump(); + + DEBUG("Shifted. Now (o=%" ASN_PRI_SIZE ", u=%" ASN_PRI_SIZE + " l=%" ASN_PRI_SIZE ")", + DynamicBuffer.offset, + DynamicBuffer.unbits, + DynamicBuffer.length); +} + +/* + * Ensure that the buffer contains at least this amount of free space. + */ +static void add_bytes_to_buffer(const void *data2add, size_t bytes) { + + if(bytes == 0) return; + + DEBUG("=> add_bytes(%" ASN_PRI_SIZE ") { o=%" ASN_PRI_SIZE + " l=%" ASN_PRI_SIZE " u=%" ASN_PRI_SIZE ", s=%" ASN_PRI_SIZE " }", + bytes, + DynamicBuffer.offset, + DynamicBuffer.length, + DynamicBuffer.unbits, + DynamicBuffer.allocated); + + if(DynamicBuffer.allocated + >= (DynamicBuffer.offset + DynamicBuffer.length + bytes)) { + DEBUG("\tNo buffer reallocation is necessary"); + } else if(bytes <= DynamicBuffer.offset) { + DEBUG("\tContents shifted by %ld", DynamicBuffer.offset); + + /* Shift the buffer contents */ + memmove(DynamicBuffer.data, + DynamicBuffer.data + DynamicBuffer.offset, + DynamicBuffer.length); + DynamicBuffer.bytes_shifted += DynamicBuffer.offset; + DynamicBuffer.offset = 0; + } else { + size_t newsize = (DynamicBuffer.allocated << 2) + bytes; + void *p = MALLOC(newsize); + if(!p) { + perror("malloc()"); + exit(EX_OSERR); + } + memcpy(p, + DynamicBuffer.data + DynamicBuffer.offset, + DynamicBuffer.length); + FREEMEM(DynamicBuffer.data); + DynamicBuffer.data = (uint8_t *)p; + DynamicBuffer.offset = 0; + DynamicBuffer.allocated = newsize; + DynamicBuffer.nreallocs++; + DEBUG("\tBuffer reallocated to %ld (%d time)", + newsize, DynamicBuffer.nreallocs); + } + + memcpy(DynamicBuffer.data + + DynamicBuffer.offset + DynamicBuffer.length, + data2add, bytes); + DynamicBuffer.length += bytes; + if(DynamicBuffer.unbits) { + int bits = DynamicBuffer.unbits; + DynamicBuffer.unbits = 0; + buffer_shift_left(DynamicBuffer.length - bytes, bits); + } + + DEBUG("<= add_bytes(%" ASN_PRI_SIZE ") { o=%" ASN_PRI_SIZE + " l=%" ASN_PRI_SIZE " u=%" ASN_PRI_SIZE ", s=%" ASN_PRI_SIZE " }", + bytes, + DynamicBuffer.offset, + DynamicBuffer.length, + DynamicBuffer.unbits, + DynamicBuffer.allocated); +} + +static int +is_syntax_PER(enum asn_transfer_syntax syntax) { + return (syntax == ATS_UNALIGNED_BASIC_PER + || syntax == ATS_UNALIGNED_CANONICAL_PER); +} + +static int +restartability_supported(enum asn_transfer_syntax syntax) { + return !is_syntax_PER(syntax); +} + +static void * +data_decode_from_file(enum asn_transfer_syntax isyntax, asn_TYPE_descriptor_t *pduType, FILE *file, const char *name, ssize_t suggested_bufsize, int on_first_pdu) { + static uint8_t *fbuf; + static ssize_t fbuf_size; + static asn_codec_ctx_t s_codec_ctx; + asn_codec_ctx_t *opt_codec_ctx = 0; + void *structure = 0; + asn_dec_rval_t rval; + size_t old_offset; + size_t new_offset; + int tolerate_eof; + size_t rd; + + if(!file) { + fprintf(stderr, "%s: %s\n", name, strerror(errno)); + errno = EINVAL; + return 0; + } + + if(opt_stack) { + s_codec_ctx.max_stack_size = opt_stack; + opt_codec_ctx = &s_codec_ctx; + } + + DEBUG("Processing %s", name); + + /* prepare the file buffer */ + if(fbuf_size != suggested_bufsize) { + fbuf = (uint8_t *)REALLOC(fbuf, suggested_bufsize); + if(!fbuf) { + perror("realloc()"); + exit(EX_OSERR); + } + fbuf_size = suggested_bufsize; + } + + if(on_first_pdu) { + DynamicBuffer.offset = 0; + DynamicBuffer.length = 0; + DynamicBuffer.unbits = 0; + DynamicBuffer.allocated = 0; + DynamicBuffer.bytes_shifted = 0; + DynamicBuffer.nreallocs = 0; + } + + old_offset = DynamicBuffer.bytes_shifted + DynamicBuffer.offset; + + /* Pretend immediate EOF */ + rval.code = RC_WMORE; + rval.consumed = 0; + + for(tolerate_eof = 1; /* Allow EOF first time buffer is non-empty */ + (rd = fread(fbuf, 1, fbuf_size, file)) + || feof(file) == 0 + || (tolerate_eof && DynamicBuffer.length) + ;) { + int ecbits = 0; /* Extra consumed bits in case of PER */ + uint8_t *i_bptr; + size_t i_size; + + /* + * Copy the data over, or use the original buffer. + */ + if(DynamicBuffer.allocated) { + /* Append new data into the existing dynamic buffer */ + add_bytes_to_buffer(fbuf, rd); + i_bptr = DynamicBuffer.data + DynamicBuffer.offset; + i_size = DynamicBuffer.length; + } else { + i_bptr = fbuf; + i_size = rd; + } + + DEBUG("Decoding %" ASN_PRI_SIZE " bytes", i_size); + +#ifdef JUNKTEST + junk_bytes_with_probability(i_bptr, i_size, opt_jprob); +#endif + + if(is_syntax_PER(isyntax) && opt_nopad) { +#ifdef ASN_DISABLE_PER_SUPPORT + rval.code = RC_FAIL; + rval.consumed = 0; +#else + rval = uper_decode(opt_codec_ctx, pduType, (void **)&structure, + i_bptr, i_size, 0, DynamicBuffer.unbits); + /* uper_decode() returns bits! */ + ecbits = rval.consumed % 8; /* Bits consumed from the last byte */ + rval.consumed >>= 3; /* Convert bits into bytes. */ +#endif + /* Non-padded PER decoder */ + } else { + rval = asn_decode(opt_codec_ctx, isyntax, pduType, + (void **)&structure, i_bptr, i_size); + } + if(rval.code == RC_WMORE && !restartability_supported(isyntax)) { + /* PER does not support restartability */ + ASN_STRUCT_FREE(*pduType, structure); + structure = 0; + rval.consumed = 0; + /* Continue accumulating data */ + } + + DEBUG("decode(%" ASN_PRI_SIZE ") consumed %" ASN_PRI_SIZE + "+%db (%" ASN_PRI_SIZE "), code %d", + DynamicBuffer.length, rval.consumed, ecbits, i_size, rval.code); + + if(DynamicBuffer.allocated == 0) { + /* + * Flush remainder into the intermediate buffer. + */ + if(rval.code != RC_FAIL && rval.consumed < rd) { + add_bytes_to_buffer(fbuf + rval.consumed, + rd - rval.consumed); + buffer_shift_left(0, ecbits); + DynamicBuffer.bytes_shifted = rval.consumed; + rval.consumed = 0; + ecbits = 0; + } + } + + /* + * Adjust position inside the source buffer. + */ + if(DynamicBuffer.allocated) { + DynamicBuffer.offset += rval.consumed; + DynamicBuffer.length -= rval.consumed; + } else { + DynamicBuffer.bytes_shifted += rval.consumed; + } + + switch(rval.code) { + case RC_OK: + if(ecbits) buffer_shift_left(0, ecbits); + DEBUG("RC_OK, finishing up with %ld+%d", + (long)rval.consumed, ecbits); + return structure; + case RC_WMORE: + DEBUG("RC_WMORE, continuing read=%ld, cons=%ld " + " with %ld..%ld-%ld..%ld", + (long)rd, + (long)rval.consumed, + (long)DynamicBuffer.offset, + (long)DynamicBuffer.length, + (long)DynamicBuffer.unbits, + (long)DynamicBuffer.allocated); + if(!rd) tolerate_eof--; + continue; + case RC_FAIL: + break; + } + break; + } + + DEBUG("Clean up partially decoded %s", pduType->name); + ASN_STRUCT_FREE(*pduType, structure); + + new_offset = DynamicBuffer.bytes_shifted + DynamicBuffer.offset; + + /* + * Print a message and return failure only if not EOF, + * unless this is our first PDU (empty file). + */ + if(on_first_pdu + || DynamicBuffer.length + || new_offset - old_offset > ((isyntax == ATS_BASIC_XER)?sizeof("\r\n")-1:0) + ) { + +#ifdef JUNKTEST + /* + * Nothing's wrong with being unable to decode junk. + * Simulate EOF. + */ + if(opt_jprob != 0.0) { + junk_failures++; + errno = 0; + return 0; + } +#endif + + DEBUG("ofp %d, no=%ld, oo=%ld, dbl=%ld", + on_first_pdu, (long)new_offset, (long)old_offset, + (long)DynamicBuffer.length); + fprintf(stderr, "%s: " + "Decode failed past byte %ld: %s\n", + name, (long)new_offset, + (rval.code == RC_WMORE) + ? "Unexpected end of input" + : "Input processing error"); +#ifndef ENOMSG +#define ENOMSG EINVAL +#endif +#ifndef EBADMSG +#define EBADMSG EINVAL +#endif + errno = (rval.code == RC_WMORE) ? ENOMSG : EBADMSG; + } else { + /* Got EOF after a few successful PDUs */ + errno = 0; + } + + return 0; +} + +/* Dump the buffer out to the specified FILE */ +static int write_out(const void *buffer, size_t size, void *key) { + FILE *fp = (FILE *)key; + return (fwrite(buffer, 1, size, fp) == size) ? 0 : -1; +} + +static int argument_is_stdin(char *av[], int idx) { + if(strcmp(av[idx], "-")) { + return 0; /* Certainly not */ + } else { + /* This might be , unless `./program -- -` */ + if(strcmp(av[-1], "--")) + return 1; + else + return 0; + } +} + +static FILE *argument_to_file(char *av[], int idx) { + return argument_is_stdin(av, idx) ? stdin : fopen(av[idx], "rb"); +} + +static char *argument_to_name(char *av[], int idx) { + return argument_is_stdin(av, idx) ? "standard input" : av[idx]; +} + +#ifdef JUNKTEST +/* + * Fill bytes with some garbage with specified probability (more or less). + */ +static void +junk_bytes_with_probability(uint8_t *buf, size_t size, double prob) { + static int junkmode; + uint8_t *ptr; + uint8_t *end; + if(opt_jprob <= 0.0) return; + for(ptr = buf, end = ptr + size; ptr < end; ptr++) { + int byte = *ptr; + if(junkmode++ & 1) { + if((((double)random() / RAND_MAX) < prob)) + byte = random() & 0xff; + } else { +#define BPROB(b) ((((double)random() / RAND_MAX) < prob) ? b : 0) + byte ^= BPROB(0x80); + byte ^= BPROB(0x40); + byte ^= BPROB(0x20); + byte ^= BPROB(0x10); + byte ^= BPROB(0x08); + byte ^= BPROB(0x04); + byte ^= BPROB(0x02); + byte ^= BPROB(0x01); + } + if(byte != *ptr) { + *ptr = byte; + } + } +} +#endif /* JUNKTEST */ + diff --git a/Vendor/asn1/include/converter-example.mk b/Vendor/asn1/include/converter-example.mk new file mode 100644 index 0000000..2e49c44 --- /dev/null +++ b/Vendor/asn1/include/converter-example.mk @@ -0,0 +1,33 @@ +include Makefile.am.libasncodec + +LIBS += -lm +CFLAGS += $(ASN_MODULE_CFLAGS) -DASN_PDU_COLLECTION -I. +ASN_LIBRARY ?= libasncodec.a +ASN_PROGRAM ?= converter-example +ASN_PROGRAM_SRCS ?= \ + converter-example.c\ + pdu_collection.c + +all: $(ASN_PROGRAM) + +$(ASN_PROGRAM): $(ASN_LIBRARY) $(ASN_PROGRAM_SRCS:.c=.o) + $(CC) $(CFLAGS) $(CPPFLAGS) -o $(ASN_PROGRAM) $(ASN_PROGRAM_SRCS:.c=.o) $(LDFLAGS) $(ASN_LIBRARY) $(LIBS) + +$(ASN_LIBRARY): $(ASN_MODULE_SRCS:.c=.o) + $(AR) rcs $@ $(ASN_MODULE_SRCS:.c=.o) + +.SUFFIXES: +.SUFFIXES: .c .o + +.c.o: + $(CC) $(CFLAGS) -o $@ -c $< + +clean: + rm -f $(ASN_PROGRAM) $(ASN_LIBRARY) + rm -f $(ASN_MODULE_SRCS:.c=.o) $(ASN_PROGRAM_SRCS:.c=.o) + +regen: regenerate-from-asn1-source + +regenerate-from-asn1-source: + asn1c -fnative-types ASN1PayloadStructure + diff --git a/Vendor/asn1/include/der_encoder.c b/Vendor/asn1/include/der_encoder.c new file mode 100644 index 0000000..2c6a6f7 --- /dev/null +++ b/Vendor/asn1/include/der_encoder.c @@ -0,0 +1,194 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include + +static ssize_t der_write_TL(ber_tlv_tag_t tag, ber_tlv_len_t len, + asn_app_consume_bytes_f *cb, void *app_key, int constructed); + +/* + * The DER encoder of any type. + */ +asn_enc_rval_t +der_encode(const asn_TYPE_descriptor_t *type_descriptor, const void *struct_ptr, + asn_app_consume_bytes_f *consume_bytes, void *app_key) { + ASN_DEBUG("DER encoder invoked for %s", + type_descriptor->name); + + /* + * Invoke type-specific encoder. + */ + return type_descriptor->op->der_encoder( + type_descriptor, struct_ptr, /* Pointer to the destination structure */ + 0, 0, consume_bytes, app_key); +} + +/* + * Argument type and callback necessary for der_encode_to_buffer(). + */ +typedef struct enc_to_buf_arg { + void *buffer; + size_t left; +} enc_to_buf_arg; +static int encode_to_buffer_cb(const void *buffer, size_t size, void *key) { + enc_to_buf_arg *arg = (enc_to_buf_arg *)key; + + if(arg->left < size) + return -1; /* Data exceeds the available buffer size */ + + memcpy(arg->buffer, buffer, size); + arg->buffer = ((char *)arg->buffer) + size; + arg->left -= size; + + return 0; +} + +/* + * A variant of the der_encode() which encodes the data into the provided buffer + */ +asn_enc_rval_t +der_encode_to_buffer(const asn_TYPE_descriptor_t *type_descriptor, + const void *struct_ptr, void *buffer, size_t buffer_size) { + enc_to_buf_arg arg; + asn_enc_rval_t ec; + + arg.buffer = buffer; + arg.left = buffer_size; + + ec = type_descriptor->op->der_encoder(type_descriptor, + struct_ptr, /* Pointer to the destination structure */ + 0, 0, encode_to_buffer_cb, &arg); + if(ec.encoded != -1) { + assert(ec.encoded == (ssize_t)(buffer_size - arg.left)); + /* Return the encoded contents size */ + } + return ec; +} + + +/* + * Write out leading TL[v] sequence according to the type definition. + */ +ssize_t +der_write_tags(const asn_TYPE_descriptor_t *sd, size_t struct_length, + int tag_mode, int last_tag_form, + ber_tlv_tag_t tag, /* EXPLICIT or IMPLICIT tag */ + asn_app_consume_bytes_f *cb, void *app_key) { +#define ASN1_DER_MAX_TAGS_COUNT 4 + ber_tlv_tag_t + tags_buf_scratch[ASN1_DER_MAX_TAGS_COUNT * sizeof(ber_tlv_tag_t)]; + ssize_t lens[ASN1_DER_MAX_TAGS_COUNT * sizeof(ssize_t)]; + const ber_tlv_tag_t *tags; /* Copy of tags stream */ + int tags_count; /* Number of tags */ + size_t overall_length; + int i; + + ASN_DEBUG("Writing tags (%s, tm=%d, tc=%d, tag=%s, mtc=%d)", + sd->name, tag_mode, sd->tags_count, + ber_tlv_tag_string(tag), + tag_mode + ?(sd->tags_count+1 + -((tag_mode == -1) && sd->tags_count)) + :sd->tags_count + ); + + if(sd->tags_count + 1 > ASN1_DER_MAX_TAGS_COUNT) { + ASN_DEBUG("System limit %d on tags count", ASN1_DER_MAX_TAGS_COUNT); + return -1; + } + + if(tag_mode) { + /* + * Instead of doing shaman dance like we do in ber_check_tags(), + * allocate a small array on the stack + * and initialize it appropriately. + */ + int stag_offset; + ber_tlv_tag_t *tags_buf = tags_buf_scratch; + tags_count = sd->tags_count + + 1 /* EXPLICIT or IMPLICIT tag is given */ + - ((tag_mode == -1) && sd->tags_count); + /* Copy tags over */ + tags_buf[0] = tag; + stag_offset = -1 + ((tag_mode == -1) && sd->tags_count); + for(i = 1; i < tags_count; i++) + tags_buf[i] = sd->tags[i + stag_offset]; + tags = tags_buf; + } else { + tags = sd->tags; + tags_count = sd->tags_count; + } + + /* No tags to write */ + if(tags_count == 0) + return 0; + + /* + * Array of tags is initialized. + * Now, compute the size of the TLV pairs, from right to left. + */ + overall_length = struct_length; + for(i = tags_count - 1; i >= 0; --i) { + lens[i] = der_write_TL(tags[i], overall_length, 0, 0, 0); + if(lens[i] == -1) return -1; + overall_length += lens[i]; + lens[i] = overall_length - lens[i]; + } + + if(!cb) return overall_length - struct_length; + + ASN_DEBUG("Encoding %s TL sequence (%d elements)", sd->name, + tags_count); + + /* + * Encode the TL sequence for real. + */ + for(i = 0; i < tags_count; i++) { + ssize_t len; + int _constr; + + /* Check if this tag happens to be constructed */ + _constr = (last_tag_form || i < (tags_count - 1)); + + len = der_write_TL(tags[i], lens[i], cb, app_key, _constr); + if(len == -1) return -1; + } + + return overall_length - struct_length; +} + +static ssize_t +der_write_TL(ber_tlv_tag_t tag, ber_tlv_len_t len, + asn_app_consume_bytes_f *cb, void *app_key, + int constructed) { + uint8_t buf[32]; + size_t size = 0; + int buf_size = cb?sizeof(buf):0; + ssize_t tmp; + + /* Serialize tag (T from TLV) into possibly zero-length buffer */ + tmp = ber_tlv_tag_serialize(tag, buf, buf_size); + if(tmp == -1 || tmp > (ssize_t)sizeof(buf)) return -1; + size += tmp; + + /* Serialize length (L from TLV) into possibly zero-length buffer */ + tmp = der_tlv_length_serialize(len, buf+size, buf_size?buf_size-size:0); + if(tmp == -1) return -1; + size += tmp; + + if(size > sizeof(buf)) + return -1; + + /* + * If callback is specified, invoke it, and check its return value. + */ + if(cb) { + if(constructed) *buf |= 0x20; + if(cb(buf, size, app_key) < 0) + return -1; + } + + return size; +} diff --git a/Vendor/asn1/include/der_encoder.h b/Vendor/asn1/include/der_encoder.h new file mode 100644 index 0000000..e93944e --- /dev/null +++ b/Vendor/asn1/include/der_encoder.h @@ -0,0 +1,68 @@ +/*- + * Copyright (c) 2003-2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _DER_ENCODER_H_ +#define _DER_ENCODER_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct asn_TYPE_descriptor_s; /* Forward declaration */ + +/* + * The DER encoder of any type. May be invoked by the application. + * Produces DER- and BER-compliant encoding. (DER is a subset of BER). + * + * NOTE: Use the ber_decode() function (ber_decoder.h) to decode data + * produced by der_encode(). + */ +asn_enc_rval_t der_encode(const struct asn_TYPE_descriptor_s *type_descriptor, + const void *struct_ptr, /* Structure to be encoded */ + asn_app_consume_bytes_f *consume_bytes_cb, + void *app_key /* Arbitrary callback argument */ +); + +/* A variant of der_encode() which encodes data into the pre-allocated buffer */ +asn_enc_rval_t der_encode_to_buffer( + const struct asn_TYPE_descriptor_s *type_descriptor, + const void *struct_ptr, /* Structure to be encoded */ + void *buffer, /* Pre-allocated buffer */ + size_t buffer_size /* Initial buffer size (maximum) */ +); + +/* + * Type of the generic DER encoder. + */ +typedef asn_enc_rval_t(der_type_encoder_f)( + const struct asn_TYPE_descriptor_s *type_descriptor, + const void *struct_ptr, /* Structure to be encoded */ + int tag_mode, /* {-1,0,1}: IMPLICIT, no, EXPLICIT */ + ber_tlv_tag_t tag, asn_app_consume_bytes_f *consume_bytes_cb, /* Callback */ + void *app_key /* Arbitrary callback argument */ +); + + +/******************************* + * INTERNALLY USEFUL FUNCTIONS * + *******************************/ + +/* + * Write out leading TL[v] sequence according to the type definition. + */ +ssize_t der_write_tags(const struct asn_TYPE_descriptor_s *type_descriptor, + size_t struct_length, + int tag_mode, /* {-1,0,1}: IMPLICIT, no, EXPLICIT */ + int last_tag_form, /* {0,!0}: prim, constructed */ + ber_tlv_tag_t tag, + asn_app_consume_bytes_f *consume_bytes_cb, + void *app_key); + +#ifdef __cplusplus +} +#endif + +#endif /* _DER_ENCODER_H_ */ diff --git a/Vendor/asn1/include/oer_decoder.c b/Vendor/asn1/include/oer_decoder.c new file mode 100644 index 0000000..0701738 --- /dev/null +++ b/Vendor/asn1/include/oer_decoder.c @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include + +/* + * The OER decoder of any type. + */ +asn_dec_rval_t +oer_decode(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *type_descriptor, void **struct_ptr, + const void *ptr, size_t size) { + asn_codec_ctx_t s_codec_ctx; + + /* + * Stack checker requires that the codec context + * must be allocated on the stack. + */ + if(opt_codec_ctx) { + if(opt_codec_ctx->max_stack_size) { + s_codec_ctx = *opt_codec_ctx; + opt_codec_ctx = &s_codec_ctx; + } + } else { + /* If context is not given, be security-conscious anyway */ + memset(&s_codec_ctx, 0, sizeof(s_codec_ctx)); + s_codec_ctx.max_stack_size = ASN__DEFAULT_STACK_MAX; + opt_codec_ctx = &s_codec_ctx; + } + + /* + * Invoke type-specific decoder. + */ + return type_descriptor->op->oer_decoder(opt_codec_ctx, type_descriptor, 0, + struct_ptr, /* Pointer to the destination structure */ + ptr, size /* Buffer and its size */ + ); +} + +/* + * Open Type is encoded as a length (#8.6) followed by that number of bytes. + * Since we're just skipping, reading the length would be enough. + */ +ssize_t +oer_open_type_skip(const void *bufptr, size_t size) { + size_t len = 0; + return oer_fetch_length(bufptr, size, &len); +} + +/* + * Read the Open Type (X.696 (08/2015), #30). + * RETURN VALUES: + * 0: More data expected than bufptr contains. + * -1: Fatal error deciphering length. + * >0: Number of bytes used from bufptr. + */ +ssize_t +oer_open_type_get(const asn_codec_ctx_t *opt_codec_ctx, + const struct asn_TYPE_descriptor_s *td, + const asn_oer_constraints_t *constraints, void **struct_ptr, + const void *bufptr, size_t size) { + asn_dec_rval_t dr; + size_t container_len = 0; + ssize_t len_len; + enum asn_struct_free_method dispose_method = + (*struct_ptr) ? ASFM_FREE_UNDERLYING_AND_RESET : ASFM_FREE_EVERYTHING; + + /* Get the size of a length determinant */ + len_len = oer_fetch_length(bufptr, size, &container_len); + if(len_len <= 0) { + return len_len; /* Error or more data expected */ + } + + /* + * len_len can't be bigger than size, but size without len_len + * should be bigger or equal to container length + */ + if(size - len_len < container_len) { + /* More data is expected */ + return 0; + } + + dr = td->op->oer_decoder(opt_codec_ctx, td, constraints, struct_ptr, + (const uint8_t *)bufptr + len_len, container_len); + if(dr.code == RC_OK) { + return len_len + container_len; + } else { + /* Even if RC_WMORE, we can't get more data into a closed container. */ + td->op->free_struct(td, *struct_ptr, dispose_method); + *struct_ptr = NULL; + return -1; + } +} + + +asn_dec_rval_t +oer_decode_primitive(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, + const asn_oer_constraints_t *constraints, void **sptr, + const void *ptr, size_t size) { + ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)*sptr; + asn_dec_rval_t rval = {RC_OK, 0}; + size_t expected_length = 0; + ssize_t len_len; + + (void)td; + (void)opt_codec_ctx; + (void)constraints; + + if(!st) { + st = (ASN__PRIMITIVE_TYPE_t *)(*sptr = CALLOC( + 1, sizeof(ASN__PRIMITIVE_TYPE_t))); + if(!st) ASN__DECODE_FAILED; + } + + + /* + * X.696 (08/2015) #27.2 + * Encode length determinant as _number of octets_, but only + * if upper bound is not equal to lower bound. + */ + len_len = oer_fetch_length(ptr, size, &expected_length); + if(len_len > 0) { + rval.consumed = len_len; + ptr = (const char *)ptr + len_len; + size -= len_len; + } else if(len_len == 0) { + ASN__DECODE_STARVED; + } else if(len_len < 0) { + ASN__DECODE_FAILED; + } + + if(size < expected_length) { + ASN__DECODE_STARVED; + } else { + uint8_t *buf = MALLOC(expected_length + 1); + if(buf == NULL) { + ASN__DECODE_FAILED; + } else { + memcpy(buf, ptr, expected_length); + buf[expected_length] = '\0'; + } + FREEMEM(st->buf); + st->buf = buf; + st->size = expected_length; + + rval.consumed += expected_length; + return rval; + } +} diff --git a/Vendor/asn1/include/oer_decoder.h b/Vendor/asn1/include/oer_decoder.h new file mode 100644 index 0000000..40992e9 --- /dev/null +++ b/Vendor/asn1/include/oer_decoder.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef OER_DECODER_H +#define OER_DECODER_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct asn_TYPE_descriptor_s; /* Forward declaration */ +struct asn_codec_ctx_s; /* Forward declaration */ + +/* + * The Octet Encoding Rules (OER, X.696 08/2015) decoder for any given type. + * This function may be invoked directly by the application. + * Parses CANONICAL-OER and BASIC-OER. + */ +asn_dec_rval_t oer_decode(const struct asn_codec_ctx_s *opt_codec_ctx, + const struct asn_TYPE_descriptor_s *type_descriptor, + void **struct_ptr, /* Pointer to a target structure's pointer */ + const void *buffer, /* Data to be decoded */ + size_t size /* Size of that buffer */ + ); + +/* + * Type of generic function which decodes the byte stream into the structure. + */ +typedef asn_dec_rval_t(oer_type_decoder_f)( + const struct asn_codec_ctx_s *opt_codec_ctx, + const struct asn_TYPE_descriptor_s *type_descriptor, + const asn_oer_constraints_t *constraints, + void **struct_ptr, + const void *buf_ptr, + size_t size); + +/* + * Swallow the Open Type (X.696 (08/2015), #30) into /dev/null. + * RETURN VALUES: + * -1: Fatal error deciphering length. + * 0: More data expected than bufptr contains. + * >0: Number of bytes used from bufptr. + */ +ssize_t oer_open_type_skip(const void *bufptr, size_t size); + +/* + * Read the Open Type (X.696 (08/2015), #30). + * RETURN VALUES: + * 0: More data expected than bufptr contains. + * -1: Fatal error deciphering length. + * >0: Number of bytes used from bufptr. + */ +ssize_t oer_open_type_get(const asn_codec_ctx_t *opt_codec_ctx, + const struct asn_TYPE_descriptor_s *td, + const asn_oer_constraints_t *constraints, + void **struct_ptr, const void *bufptr, size_t size); + +/* + * Length-prefixed buffer decoding for primitive types. + */ +oer_type_decoder_f oer_decode_primitive; + + +#ifdef __cplusplus +} +#endif + +#endif /* OER_DECODER_H */ diff --git a/Vendor/asn1/include/oer_encoder.c b/Vendor/asn1/include/oer_encoder.c new file mode 100644 index 0000000..895aed4 --- /dev/null +++ b/Vendor/asn1/include/oer_encoder.c @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include + +/* + * The OER encoder of any type. + */ +asn_enc_rval_t +oer_encode(const asn_TYPE_descriptor_t *type_descriptor, const void *struct_ptr, + asn_app_consume_bytes_f *consume_bytes, void *app_key) { + ASN_DEBUG("OER encoder invoked for %s", type_descriptor->name); + + /* + * Invoke type-specific encoder. + */ + return type_descriptor->op->oer_encoder( + type_descriptor, 0, + struct_ptr, /* Pointer to the destination structure */ + consume_bytes, app_key); +} + +/* + * Argument type and callback necessary for oer_encode_to_buffer(). + */ +typedef struct enc_to_buf_arg { + void *buffer; + size_t left; +} enc_to_buf_arg; +static int +encode_to_buffer_cb(const void *buffer, size_t size, void *key) { + enc_to_buf_arg *arg = (enc_to_buf_arg *)key; + + if(arg->left < size) return -1; /* Data exceeds the available buffer size */ + + memcpy(arg->buffer, buffer, size); + arg->buffer = ((char *)arg->buffer) + size; + arg->left -= size; + + return 0; +} + +/* + * A variant of the oer_encode() which encodes the data into the provided buffer + */ +asn_enc_rval_t +oer_encode_to_buffer(const asn_TYPE_descriptor_t *type_descriptor, + const asn_oer_constraints_t *constraints, + const void *struct_ptr, /* Structure to be encoded */ + void *buffer, /* Pre-allocated buffer */ + size_t buffer_size /* Initial buffer size (maximum) */ +) { + enc_to_buf_arg arg; + asn_enc_rval_t ec; + + arg.buffer = buffer; + arg.left = buffer_size; + + if(type_descriptor->op->oer_encoder == NULL) { + ec.encoded = -1; + ec.failed_type = type_descriptor; + ec.structure_ptr = struct_ptr; + ASN_DEBUG("OER encoder is not defined for %s", + type_descriptor->name); + } else { + ec = type_descriptor->op->oer_encoder( + type_descriptor, constraints, + struct_ptr, /* Pointer to the destination structure */ + encode_to_buffer_cb, &arg); + if(ec.encoded != -1) { + assert(ec.encoded == (ssize_t)(buffer_size - arg.left)); + /* Return the encoded contents size */ + } + } + return ec; +} + +asn_enc_rval_t +oer_encode_primitive(const asn_TYPE_descriptor_t *td, + const asn_oer_constraints_t *constraints, const void *sptr, + asn_app_consume_bytes_f *cb, void *app_key) { + const ASN__PRIMITIVE_TYPE_t *st = (const ASN__PRIMITIVE_TYPE_t *)sptr; + asn_enc_rval_t er = {0, 0, 0}; + ssize_t ret; + + (void)constraints; + + if(!st) ASN__ENCODE_FAILED; + + ASN_DEBUG("Encoding %s (%" ASN_PRI_SIZE " bytes)", td ? td->name : "", st->size); + + /* + * X.696 (08/2015) #27.2 + */ + ret = oer_serialize_length(st->size, cb, app_key); + if(ret < 0) { + ASN__ENCODE_FAILED; + } + er.encoded += ret; + + er.encoded += st->size; + if(cb(st->buf, st->size, app_key) < 0) { + ASN__ENCODE_FAILED; + } else { + ASN__ENCODED_OK(er); + } +} + +static int +oer__count_bytes(const void *buffer, size_t size, void *bytes_ptr) { + size_t *bytes = bytes_ptr; + (void)buffer; + *bytes += size; + return 0; +} + +ssize_t +oer_open_type_put(const asn_TYPE_descriptor_t *td, + const asn_oer_constraints_t *constraints, const void *sptr, + asn_app_consume_bytes_f *cb, void *app_key) { + size_t serialized_byte_count = 0; + asn_enc_rval_t er; + ssize_t len_len; + + er = td->op->oer_encoder(td, constraints, sptr, oer__count_bytes, + &serialized_byte_count); + if(er.encoded < 0) return -1; + assert(serialized_byte_count == (size_t)er.encoded); + + len_len = oer_serialize_length(serialized_byte_count, cb, app_key); + if(len_len == -1) return -1; + + er = td->op->oer_encoder(td, constraints, sptr, cb, app_key); + if(er.encoded < 0) return -1; + assert(serialized_byte_count == (size_t)er.encoded); + + return len_len + er.encoded; +} + diff --git a/Vendor/asn1/include/oer_encoder.h b/Vendor/asn1/include/oer_encoder.h new file mode 100644 index 0000000..6a7b681 --- /dev/null +++ b/Vendor/asn1/include/oer_encoder.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef OER_ENCODER_H +#define OER_ENCODER_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct asn_TYPE_descriptor_s; /* Forward declaration */ + +/* + * The Octet Encoding Rules (OER, X.696 08/2015) encoder for any type. + * This function may be invoked directly by the application. + * Produces CANONICAL-OER output compatible with CANONICAL-OER + * and BASIC-OER decoders. + */ +asn_enc_rval_t oer_encode(const struct asn_TYPE_descriptor_s *type_descriptor, + const void *struct_ptr, /* Structure to be encoded */ + asn_app_consume_bytes_f *consume_bytes_cb, + void *app_key /* Arbitrary callback argument */ +); + +/* A variant of oer_encode() which encodes data into the pre-allocated buffer */ +asn_enc_rval_t oer_encode_to_buffer( + const struct asn_TYPE_descriptor_s *type_descriptor, + const asn_oer_constraints_t *constraints, + const void *struct_ptr, /* Structure to be encoded */ + void *buffer, /* Pre-allocated buffer */ + size_t buffer_size /* Initial buffer size (maximum) */ +); + +/* + * Type of the generic OER encoder. + */ +typedef asn_enc_rval_t(oer_type_encoder_f)( + const struct asn_TYPE_descriptor_s *type_descriptor, + const asn_oer_constraints_t *constraints, + const void *struct_ptr, /* Structure to be encoded */ + asn_app_consume_bytes_f *consume_bytes_cb, /* Callback */ + void *app_key /* Arbitrary callback argument */ +); + +/* + * Write out the Open Type (X.696 (08/2015), #30). + * RETURN VALUES: + * -1: Fatal error encoding the type. + * >0: Number of bytes serialized. + */ +ssize_t oer_open_type_put(const struct asn_TYPE_descriptor_s *td, + const asn_oer_constraints_t *constraints, + const void *struct_ptr, + asn_app_consume_bytes_f *consume_bytes_cb, + void *app_key); + + +/* + * Length-prefixed buffer encoding for primitive types. + */ +oer_type_encoder_f oer_encode_primitive; + +#ifdef __cplusplus +} +#endif + +#endif /* OER_ENCODER_H */ diff --git a/Vendor/asn1/include/oer_support.c b/Vendor/asn1/include/oer_support.c new file mode 100644 index 0000000..b15a3bc --- /dev/null +++ b/Vendor/asn1/include/oer_support.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2017 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include + +#include + +/* + * Fetch the length determinant (X.696 08/2015, #8.6) into *len_r. + * RETURN VALUES: + * 0: More data expected than bufptr contains. + * -1: Fatal error deciphering length. + * >0: Number of bytes used from bufptr. + */ +ssize_t +oer_fetch_length(const void *bufptr, size_t size, size_t *len_r) { + uint8_t first_byte; + size_t len_len; /* Length of the length determinant */ + const uint8_t *b; + const uint8_t *bend; + size_t len; + + if(size == 0) { + *len_r = 0; + return 0; + } + + first_byte = *(const uint8_t *)bufptr; + if((first_byte & 0x80) == 0) { /* Short form */ + *len_r = first_byte; /* 0..127 */ + return 1; + } + + len_len = (first_byte & 0x7f); + if((1 + len_len) > size) { + *len_r = 0; + return 0; + } + + b = (const uint8_t *)bufptr + 1; + bend = b + len_len; + + for(; b < bend && *b == 0; b++) { + /* Skip the leading 0-bytes */ + } + + if((bend - b) > (ssize_t)sizeof(size_t)) { + /* Length is not representable by the native size_t type */ + *len_r = 0; + return -1; + } + + for(len = 0; b < bend; b++) { + len = (len << 8) + *b; + } + + if(len > RSIZE_MAX) { /* A bit of C11 validation */ + *len_r = 0; + return -1; + } + + *len_r = len; + assert(len_len + 1 == (size_t)(bend - (const uint8_t *)bufptr)); + return len_len + 1; +} + + +/* + * Serialize OER length. Returns the number of bytes serialized + * or -1 if a given callback returned with negative result. + */ +ssize_t +oer_serialize_length(size_t length, asn_app_consume_bytes_f *cb, + void *app_key) { + uint8_t scratch[1 + sizeof(length)]; + uint8_t *sp = scratch; + int littleEndian = 1; /* Run-time detection */ + const uint8_t *pstart; + const uint8_t *pend; + const uint8_t *p; + int add; + + if(length <= 127) { + uint8_t b = length; + if(cb(&b, 1, app_key) < 0) { + return -1; + } + return 1; + } + + if(*(char *)&littleEndian) { + pstart = (const uint8_t *)&length + sizeof(length) - 1; + pend = (const uint8_t *)&length; + add = -1; + } else { + pstart = (const uint8_t *)&length; + pend = pstart + sizeof(length); + add = 1; + } + + for(p = pstart; p != pend; p += add) { + /* Skip leading zeros. */ + if(*p) break; + } + + for(sp = scratch + 1; ; p += add) { + *sp++ = *p; + if(p == pend) break; + } + assert((sp - scratch) - 1 <= 0x7f); + scratch[0] = 0x80 + ((sp - scratch) - 1); + + if(cb(scratch, sp - scratch, app_key) < 0) { + return -1; + } + + return sp - scratch; +} + diff --git a/Vendor/asn1/include/oer_support.h b/Vendor/asn1/include/oer_support.h new file mode 100644 index 0000000..dbc9b5f --- /dev/null +++ b/Vendor/asn1/include/oer_support.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef OER_SUPPORT_H +#define OER_SUPPORT_H + +#include /* Platform-specific types */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Pre-computed OER constraints. + */ +typedef struct asn_oer_constraint_number_s { + unsigned width; /* ±8,4,2,1 fixed bytes */ + unsigned positive; /* 1 for unsigned number, 0 for signed */ +} asn_oer_constraint_number_t; +typedef struct asn_oer_constraints_s { + asn_oer_constraint_number_t value; + ssize_t size; /* -1 (no constraint) or >= 0 */ +} asn_oer_constraints_t; + + +/* + * Fetch the length determinant (X.696 (08/2015), #8.6) into *len_r. + * RETURN VALUES: + * 0: More data expected than bufptr contains. + * -1: Fatal error deciphering length. + * >0: Number of bytes used from bufptr. + */ +ssize_t oer_fetch_length(const void *bufptr, size_t size, size_t *len_r); + +/* + * Serialize OER length. Returns the number of bytes serialized + * or -1 if a given callback returned with negative result. + */ +ssize_t oer_serialize_length(size_t length, asn_app_consume_bytes_f *cb, void *app_key); + + +#ifdef __cplusplus +} +#endif + +#endif /* OER_SUPPORT_H */ diff --git a/Vendor/asn1/include/pdu_collection.c b/Vendor/asn1/include/pdu_collection.c new file mode 100644 index 0000000..a6e1e1a --- /dev/null +++ b/Vendor/asn1/include/pdu_collection.c @@ -0,0 +1,15 @@ +/* + * Generated by asn1c-0.9.29 (http://lionet.info/asn1c) + */ + +struct asn_TYPE_descriptor_s; /* Forward declaration */ + +extern struct asn_TYPE_descriptor_s asn_DEF_Payload; + + +struct asn_TYPE_descriptor_s *asn_pdu_collection[] = { + /* From module ReceiptModule in ASN1PayloadStructure */ + &asn_DEF_Payload, + 0 +}; + diff --git a/Vendor/asn1/include/per_decoder.c b/Vendor/asn1/include/per_decoder.c new file mode 100644 index 0000000..a9051fb --- /dev/null +++ b/Vendor/asn1/include/per_decoder.c @@ -0,0 +1,97 @@ +#include +#include +#include + +/* + * Decode a "Production of a complete encoding", X.691#10.1. + * The complete encoding contains at least one byte, and is an integral + * multiple of 8 bytes. + */ +asn_dec_rval_t +uper_decode_complete(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, void **sptr, + const void *buffer, size_t size) { + asn_dec_rval_t rval; + + rval = uper_decode(opt_codec_ctx, td, sptr, buffer, size, 0, 0); + if(rval.consumed) { + /* + * We've always given 8-aligned data, + * so convert bits to integral bytes. + */ + rval.consumed += 7; + rval.consumed >>= 3; + } else if(rval.code == RC_OK) { + if(size) { + if(((const uint8_t *)buffer)[0] == 0) { + rval.consumed = 1; /* 1 byte */ + } else { + ASN_DEBUG("Expecting single zeroed byte"); + rval.code = RC_FAIL; + } + } else { + /* Must contain at least 8 bits. */ + rval.code = RC_WMORE; + } + } + + return rval; +} + +asn_dec_rval_t +uper_decode(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, void **sptr, const void *buffer, + size_t size, int skip_bits, int unused_bits) { + asn_codec_ctx_t s_codec_ctx; + asn_dec_rval_t rval; + asn_per_data_t pd; + + if(skip_bits < 0 || skip_bits > 7 + || unused_bits < 0 || unused_bits > 7 + || (unused_bits > 0 && !size)) + ASN__DECODE_FAILED; + + /* + * Stack checker requires that the codec context + * must be allocated on the stack. + */ + if(opt_codec_ctx) { + if(opt_codec_ctx->max_stack_size) { + s_codec_ctx = *opt_codec_ctx; + opt_codec_ctx = &s_codec_ctx; + } + } else { + /* If context is not given, be security-conscious anyway */ + memset(&s_codec_ctx, 0, sizeof(s_codec_ctx)); + s_codec_ctx.max_stack_size = ASN__DEFAULT_STACK_MAX; + opt_codec_ctx = &s_codec_ctx; + } + + /* Fill in the position indicator */ + memset(&pd, 0, sizeof(pd)); + pd.buffer = (const uint8_t *)buffer; + pd.nboff = skip_bits; + pd.nbits = 8 * size - unused_bits; /* 8 is CHAR_BIT from */ + if(pd.nboff > pd.nbits) + ASN__DECODE_FAILED; + + /* + * Invoke type-specific decoder. + */ + if(!td->op->uper_decoder) + ASN__DECODE_FAILED; /* PER is not compiled in */ + rval = td->op->uper_decoder(opt_codec_ctx, td, 0, sptr, &pd); + if(rval.code == RC_OK) { + /* Return the number of consumed bits */ + rval.consumed = ((pd.buffer - (const uint8_t *)buffer) << 3) + + pd.nboff - skip_bits; + ASN_DEBUG("PER decoding consumed %ld, counted %ld", + (long)rval.consumed, (long)pd.moved); + assert(rval.consumed == pd.moved); + } else { + /* PER codec is not a restartable */ + rval.consumed = 0; + } + return rval; +} + diff --git a/Vendor/asn1/include/per_decoder.h b/Vendor/asn1/include/per_decoder.h new file mode 100644 index 0000000..710f4ee --- /dev/null +++ b/Vendor/asn1/include/per_decoder.h @@ -0,0 +1,57 @@ +/*- + * Copyright (c) 2005-2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _PER_DECODER_H_ +#define _PER_DECODER_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct asn_TYPE_descriptor_s; /* Forward declaration */ + +/* + * Unaligned PER decoder of a "complete encoding" as per X.691 (08/2015) #11.1. + * On success, this call always returns (.consumed >= 1), as per #11.1.3. + */ +asn_dec_rval_t uper_decode_complete( + const struct asn_codec_ctx_s *opt_codec_ctx, + const struct asn_TYPE_descriptor_s *type_descriptor, /* Type to decode */ + void **struct_ptr, /* Pointer to a target structure's pointer */ + const void *buffer, /* Data to be decoded */ + size_t size /* Size of data buffer */ +); + +/* + * Unaligned PER decoder of any ASN.1 type. May be invoked by the application. + * WARNING: This call returns the number of BITS read from the stream. Beware. + */ +asn_dec_rval_t uper_decode( + const struct asn_codec_ctx_s *opt_codec_ctx, + const struct asn_TYPE_descriptor_s *type_descriptor, /* Type to decode */ + void **struct_ptr, /* Pointer to a target structure's pointer */ + const void *buffer, /* Data to be decoded */ + size_t size, /* Size of the input data buffer, in bytes */ + int skip_bits, /* Number of unused leading bits, 0..7 */ + int unused_bits /* Number of unused tailing bits, 0..7 */ +); + + +/* + * Type of the type-specific PER decoder function. + */ +typedef asn_dec_rval_t(per_type_decoder_f)( + const asn_codec_ctx_t *opt_codec_ctx, + const struct asn_TYPE_descriptor_s *type_descriptor, + const asn_per_constraints_t *constraints, void **struct_ptr, + asn_per_data_t *per_data); + +#ifdef __cplusplus +} +#endif + +#endif /* _PER_DECODER_H_ */ diff --git a/Vendor/asn1/include/per_encoder.c b/Vendor/asn1/include/per_encoder.c new file mode 100644 index 0000000..86aec4e --- /dev/null +++ b/Vendor/asn1/include/per_encoder.c @@ -0,0 +1,165 @@ +#include +#include +#include + +static int _uper_encode_flush_outp(asn_per_outp_t *po); + +static int +ignore_output(const void *data, size_t size, void *app_key) { + (void)data; + (void)size; + (void)app_key; + return 0; +} + +asn_enc_rval_t +uper_encode(const asn_TYPE_descriptor_t *td, + const asn_per_constraints_t *constraints, const void *sptr, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_per_outp_t po; + asn_enc_rval_t er; + + /* + * Invoke type-specific encoder. + */ + if(!td || !td->op->uper_encoder) + ASN__ENCODE_FAILED; /* PER is not compiled in */ + + po.buffer = po.tmpspace; + po.nboff = 0; + po.nbits = 8 * sizeof(po.tmpspace); + po.output = cb ? cb : ignore_output; + po.op_key = app_key; + po.flushed_bytes = 0; + + er = td->op->uper_encoder(td, constraints, sptr, &po); + if(er.encoded != -1) { + size_t bits_to_flush; + + bits_to_flush = ((po.buffer - po.tmpspace) << 3) + po.nboff; + + /* Set number of bits encoded to a firm value */ + er.encoded = (po.flushed_bytes << 3) + bits_to_flush; + + if(_uper_encode_flush_outp(&po)) ASN__ENCODE_FAILED; + } + + return er; +} + +/* + * Argument type and callback necessary for uper_encode_to_buffer(). + */ +typedef struct enc_to_buf_arg { + void *buffer; + size_t left; +} enc_to_buf_arg; +static int encode_to_buffer_cb(const void *buffer, size_t size, void *key) { + enc_to_buf_arg *arg = (enc_to_buf_arg *)key; + + if(arg->left < size) + return -1; /* Data exceeds the available buffer size */ + + memcpy(arg->buffer, buffer, size); + arg->buffer = ((char *)arg->buffer) + size; + arg->left -= size; + + return 0; +} + +asn_enc_rval_t +uper_encode_to_buffer(const asn_TYPE_descriptor_t *td, + const asn_per_constraints_t *constraints, + const void *sptr, void *buffer, size_t buffer_size) { + enc_to_buf_arg key; + + key.buffer = buffer; + key.left = buffer_size; + + if(td) ASN_DEBUG("Encoding \"%s\" using UNALIGNED PER", td->name); + + return uper_encode(td, constraints, sptr, encode_to_buffer_cb, &key); +} + +typedef struct enc_dyn_arg { + void *buffer; + size_t length; + size_t allocated; +} enc_dyn_arg; +static int +encode_dyn_cb(const void *buffer, size_t size, void *key) { + enc_dyn_arg *arg = key; + if(arg->length + size >= arg->allocated) { + size_t new_size = arg->allocated ? arg->allocated : 8; + void *p; + + do { + new_size <<= 2; + } while(arg->length + size >= new_size); + + p = REALLOC(arg->buffer, new_size); + if(!p) { + FREEMEM(arg->buffer); + memset(arg, 0, sizeof(*arg)); + return -1; + } + arg->buffer = p; + arg->allocated = new_size; + } + memcpy(((char *)arg->buffer) + arg->length, buffer, size); + arg->length += size; + return 0; +} +ssize_t +uper_encode_to_new_buffer(const asn_TYPE_descriptor_t *td, + const asn_per_constraints_t *constraints, + const void *sptr, void **buffer_r) { + asn_enc_rval_t er; + enc_dyn_arg key; + + memset(&key, 0, sizeof(key)); + + er = uper_encode(td, constraints, sptr, encode_dyn_cb, &key); + switch(er.encoded) { + case -1: + FREEMEM(key.buffer); + return -1; + case 0: + FREEMEM(key.buffer); + key.buffer = MALLOC(1); + if(key.buffer) { + *(char *)key.buffer = '\0'; + *buffer_r = key.buffer; + return 1; + } else { + return -1; + } + default: + *buffer_r = key.buffer; + ASN_DEBUG("Complete encoded in %ld bits", (long)er.encoded); + return ((er.encoded + 7) >> 3); + } +} + +/* + * Internally useful functions. + */ + +/* Flush partially filled buffer */ +static int +_uper_encode_flush_outp(asn_per_outp_t *po) { + uint8_t *buf; + + if(po->nboff == 0 && po->buffer == po->tmpspace) + return 0; + + buf = po->buffer + (po->nboff >> 3); + /* Make sure we account for the last, partially filled */ + if(po->nboff & 0x07) { + buf[0] &= 0xff << (8 - (po->nboff & 0x07)); + buf++; + } + + return po->output(po->tmpspace, buf - po->tmpspace, po->op_key); +} + diff --git a/Vendor/asn1/include/per_encoder.h b/Vendor/asn1/include/per_encoder.h new file mode 100644 index 0000000..44d8e8a --- /dev/null +++ b/Vendor/asn1/include/per_encoder.h @@ -0,0 +1,70 @@ +/*- + * Copyright (c) 2006-2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _PER_ENCODER_H_ +#define _PER_ENCODER_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct asn_TYPE_descriptor_s; /* Forward declaration */ + +/* + * Unaligned PER encoder of any ASN.1 type. May be invoked by the application. + * WARNING: This function returns the number of encoded bits in the .encoded + * field of the return value. Use the following formula to convert to bytes: + * bytes = ((.encoded + 7) / 8) + */ +asn_enc_rval_t uper_encode( + const struct asn_TYPE_descriptor_s *type_descriptor, + const asn_per_constraints_t *constraints, + const void *struct_ptr, /* Structure to be encoded */ + asn_app_consume_bytes_f *consume_bytes_cb, /* Data collector */ + void *app_key /* Arbitrary callback argument */ +); + +/* + * A variant of uper_encode() which encodes data into the existing buffer + * WARNING: This function returns the number of encoded bits in the .encoded + * field of the return value. + */ +asn_enc_rval_t uper_encode_to_buffer( + const struct asn_TYPE_descriptor_s *type_descriptor, + const asn_per_constraints_t *constraints, + const void *struct_ptr, /* Structure to be encoded */ + void *buffer, /* Pre-allocated buffer */ + size_t buffer_size /* Initial buffer size (max) */ +); + +/* + * A variant of uper_encode_to_buffer() which allocates buffer itself. + * Returns the number of bytes in the buffer or -1 in case of failure. + * WARNING: This function produces a "Production of the complete encoding", + * with length of at least one octet. Contrast this to precise bit-packing + * encoding of uper_encode() and uper_encode_to_buffer(). + */ +ssize_t uper_encode_to_new_buffer( + const struct asn_TYPE_descriptor_s *type_descriptor, + const asn_per_constraints_t *constraints, + const void *struct_ptr, /* Structure to be encoded */ + void **buffer_r /* Buffer allocated and returned */ +); + +/* + * Type of the generic PER encoder function. + */ +typedef asn_enc_rval_t(per_type_encoder_f)( + const struct asn_TYPE_descriptor_s *type_descriptor, + const asn_per_constraints_t *constraints, const void *struct_ptr, + asn_per_outp_t *per_output); + +#ifdef __cplusplus +} +#endif + +#endif /* _PER_ENCODER_H_ */ diff --git a/Vendor/asn1/include/per_opentype.c b/Vendor/asn1/include/per_opentype.c new file mode 100644 index 0000000..f86dad7 --- /dev/null +++ b/Vendor/asn1/include/per_opentype.c @@ -0,0 +1,396 @@ +/* + * Copyright (c) 2007 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include +#include + +typedef struct uper_ugot_key { + asn_per_data_t oldpd; /* Old per data source */ + size_t unclaimed; + size_t ot_moved; /* Number of bits moved by OT processing */ + int repeat; +} uper_ugot_key; + +static int uper_ugot_refill(asn_per_data_t *pd); +static int per_skip_bits(asn_per_data_t *pd, int skip_nbits); +static asn_dec_rval_t uper_sot_suck(const asn_codec_ctx_t *, + const asn_TYPE_descriptor_t *td, + const asn_per_constraints_t *constraints, + void **sptr, asn_per_data_t *pd); + +/* + * Encode an "open type field". + * #10.1, #10.2 + */ +int +uper_open_type_put(const asn_TYPE_descriptor_t *td, + const asn_per_constraints_t *constraints, const void *sptr, + asn_per_outp_t *po) { + void *buf; + void *bptr; + ssize_t size; + + ASN_DEBUG("Open type put %s ...", td->name); + + size = uper_encode_to_new_buffer(td, constraints, sptr, &buf); + if(size <= 0) return -1; + + ASN_DEBUG("Open type put %s of length %" ASN_PRI_SSIZE " + overhead (1byte?)", td->name, + size); + + bptr = buf; + do { + int need_eom = 0; + ssize_t may_save = uper_put_length(po, size, &need_eom); + ASN_DEBUG("Prepending length %" ASN_PRI_SSIZE + " to %s and allowing to save %" ASN_PRI_SSIZE, + size, td->name, may_save); + if(may_save < 0) break; + if(per_put_many_bits(po, bptr, may_save * 8)) break; + bptr = (char *)bptr + may_save; + size -= may_save; + if(need_eom && uper_put_length(po, 0, 0)) { + FREEMEM(buf); + return -1; + } + } while(size); + + FREEMEM(buf); + if(size) return -1; + + return 0; +} + +static asn_dec_rval_t +uper_open_type_get_simple(const asn_codec_ctx_t *ctx, + const asn_TYPE_descriptor_t *td, + const asn_per_constraints_t *constraints, void **sptr, + asn_per_data_t *pd) { + asn_dec_rval_t rv; + ssize_t chunk_bytes; + int repeat; + uint8_t *buf = 0; + size_t bufLen = 0; + size_t bufSize = 0; + asn_per_data_t spd; + size_t padding; + + ASN__STACK_OVERFLOW_CHECK(ctx); + + ASN_DEBUG("Getting open type %s...", td->name); + + do { + chunk_bytes = uper_get_length(pd, -1, 0, &repeat); + if(chunk_bytes < 0) { + FREEMEM(buf); + ASN__DECODE_STARVED; + } + if(bufLen + chunk_bytes > bufSize) { + void *ptr; + bufSize = chunk_bytes + (bufSize << 2); + ptr = REALLOC(buf, bufSize); + if(!ptr) { + FREEMEM(buf); + ASN__DECODE_FAILED; + } + buf = ptr; + } + if(per_get_many_bits(pd, buf + bufLen, 0, chunk_bytes << 3)) { + FREEMEM(buf); + ASN__DECODE_STARVED; + } + bufLen += chunk_bytes; + } while(repeat); + + ASN_DEBUG("Getting open type %s encoded in %ld bytes", td->name, + (long)bufLen); + + memset(&spd, 0, sizeof(spd)); + spd.buffer = buf; + spd.nbits = bufLen << 3; + + ASN_DEBUG_INDENT_ADD(+4); + rv = td->op->uper_decoder(ctx, td, constraints, sptr, &spd); + ASN_DEBUG_INDENT_ADD(-4); + + if(rv.code == RC_OK) { + /* Check padding validity */ + padding = spd.nbits - spd.nboff; + if ((padding < 8 || + /* X.691#10.1.3 */ + (spd.nboff == 0 && spd.nbits == 8 && spd.buffer == buf)) && + per_get_few_bits(&spd, padding) == 0) { + /* Everything is cool */ + FREEMEM(buf); + return rv; + } + FREEMEM(buf); + if(padding >= 8) { + ASN_DEBUG("Too large padding %d in open type", (int)padding); + ASN__DECODE_FAILED; + } else { + ASN_DEBUG("Non-zero padding"); + ASN__DECODE_FAILED; + } + } else { + FREEMEM(buf); + /* rv.code could be RC_WMORE, nonsense in this context */ + rv.code = RC_FAIL; /* Noone would give us more */ + } + + return rv; +} + +static asn_dec_rval_t CC_NOTUSED +uper_open_type_get_complex(const asn_codec_ctx_t *ctx, + const asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void **sptr, + asn_per_data_t *pd) { + uper_ugot_key arg; + asn_dec_rval_t rv; + ssize_t padding; + + ASN__STACK_OVERFLOW_CHECK(ctx); + + ASN_DEBUG("Getting open type %s from %s", td->name, + asn_bit_data_string(pd)); + arg.oldpd = *pd; + arg.unclaimed = 0; + arg.ot_moved = 0; + arg.repeat = 1; + pd->refill = uper_ugot_refill; + pd->refill_key = &arg; + pd->nbits = pd->nboff; /* 0 good bits at this point, will refill */ + pd->moved = 0; /* This now counts the open type size in bits */ + + ASN_DEBUG_INDENT_ADD(+4); + rv = td->op->uper_decoder(ctx, td, constraints, sptr, pd); + ASN_DEBUG_INDENT_ADD(-4); + +#define UPDRESTOREPD do { \ + /* buffer and nboff are valid, preserve them. */ \ + pd->nbits = arg.oldpd.nbits - (pd->moved - arg.ot_moved); \ + pd->moved = arg.oldpd.moved + (pd->moved - arg.ot_moved); \ + pd->refill = arg.oldpd.refill; \ + pd->refill_key = arg.oldpd.refill_key; \ + } while(0) + + if(rv.code != RC_OK) { + UPDRESTOREPD; + return rv; + } + + ASN_DEBUG("OpenType %s pd%s old%s unclaimed=%d, repeat=%d", td->name, + asn_bit_data_string(pd), + asn_bit_data_string(&arg.oldpd), + (int)arg.unclaimed, (int)arg.repeat); + + padding = pd->moved % 8; + if(padding) { + int32_t pvalue; + if(padding > 7) { + ASN_DEBUG("Too large padding %d in open type", + (int)padding); + rv.code = RC_FAIL; + UPDRESTOREPD; + return rv; + } + padding = 8 - padding; + ASN_DEBUG("Getting padding of %d bits", (int)padding); + pvalue = per_get_few_bits(pd, padding); + switch(pvalue) { + case -1: + ASN_DEBUG("Padding skip failed"); + UPDRESTOREPD; + ASN__DECODE_STARVED; + case 0: break; + default: + ASN_DEBUG("Non-blank padding (%d bits 0x%02x)", + (int)padding, (int)pvalue); + UPDRESTOREPD; + ASN__DECODE_FAILED; + } + } + if(pd->nboff != pd->nbits) { + ASN_DEBUG("Open type %s overhead pd%s old%s", td->name, + asn_bit_data_string(pd), asn_bit_data_string(&arg.oldpd)); + if(1) { + UPDRESTOREPD; + ASN__DECODE_FAILED; + } else { + arg.unclaimed += pd->nbits - pd->nboff; + } + } + + /* Adjust pd back so it points to original data */ + UPDRESTOREPD; + + /* Skip data not consumed by the decoder */ + if(arg.unclaimed) { + ASN_DEBUG("Getting unclaimed %d", (int)arg.unclaimed); + switch(per_skip_bits(pd, arg.unclaimed)) { + case -1: + ASN_DEBUG("Claim of %d failed", (int)arg.unclaimed); + ASN__DECODE_STARVED; + case 0: + ASN_DEBUG("Got claim of %d", (int)arg.unclaimed); + break; + default: + /* Padding must be blank */ + ASN_DEBUG("Non-blank unconsumed padding"); + ASN__DECODE_FAILED; + } + arg.unclaimed = 0; + } + + if(arg.repeat) { + ASN_DEBUG("Not consumed the whole thing"); + rv.code = RC_FAIL; + return rv; + } + + return rv; +} + + +asn_dec_rval_t +uper_open_type_get(const asn_codec_ctx_t *ctx, const asn_TYPE_descriptor_t *td, + const asn_per_constraints_t *constraints, void **sptr, + asn_per_data_t *pd) { + return uper_open_type_get_simple(ctx, td, constraints, sptr, pd); +} + +int +uper_open_type_skip(const asn_codec_ctx_t *ctx, asn_per_data_t *pd) { + asn_TYPE_descriptor_t s_td; + asn_TYPE_operation_t s_op; + asn_dec_rval_t rv; + + s_td.name = ""; + s_td.op = &s_op; + s_op.uper_decoder = uper_sot_suck; + + rv = uper_open_type_get(ctx, &s_td, 0, 0, pd); + if(rv.code != RC_OK) + return -1; + else + return 0; +} + +/* + * Internal functions. + */ + +static asn_dec_rval_t +uper_sot_suck(const asn_codec_ctx_t *ctx, const asn_TYPE_descriptor_t *td, + const asn_per_constraints_t *constraints, void **sptr, + asn_per_data_t *pd) { + asn_dec_rval_t rv; + + (void)ctx; + (void)td; + (void)constraints; + (void)sptr; + + while(per_get_few_bits(pd, 24) >= 0); + + rv.code = RC_OK; + rv.consumed = pd->moved; + + return rv; +} + +static int +uper_ugot_refill(asn_per_data_t *pd) { + uper_ugot_key *arg = pd->refill_key; + ssize_t next_chunk_bytes, next_chunk_bits; + ssize_t avail; + + asn_per_data_t *oldpd = &arg->oldpd; + + ASN_DEBUG("REFILLING pd->moved=%ld, oldpd->moved=%ld", + (long)pd->moved, (long)oldpd->moved); + + /* Advance our position to where pd is */ + oldpd->buffer = pd->buffer; + oldpd->nboff = pd->nboff; + oldpd->nbits -= pd->moved - arg->ot_moved; + oldpd->moved += pd->moved - arg->ot_moved; + arg->ot_moved = pd->moved; + + if(arg->unclaimed) { + /* Refill the container */ + if(per_get_few_bits(oldpd, 1)) + return -1; + if(oldpd->nboff == 0) { + assert(0); + return -1; + } + pd->buffer = oldpd->buffer; + pd->nboff = oldpd->nboff - 1; + pd->nbits = oldpd->nbits; + ASN_DEBUG("UNCLAIMED <- return from (pd->moved=%ld)", + (long)pd->moved); + return 0; + } + + if(!arg->repeat) { + ASN_DEBUG("Want more but refill doesn't have it"); + return -1; + } + + next_chunk_bytes = uper_get_length(oldpd, -1, 0, &arg->repeat); + ASN_DEBUG("Open type LENGTH %ld bytes at off %ld, repeat %ld", + (long)next_chunk_bytes, (long)oldpd->moved, (long)arg->repeat); + if(next_chunk_bytes < 0) return -1; + if(next_chunk_bytes == 0) { + pd->refill = 0; /* No more refills, naturally */ + assert(!arg->repeat); /* Implementation guarantee */ + } + next_chunk_bits = next_chunk_bytes << 3; + avail = oldpd->nbits - oldpd->nboff; + if(avail >= next_chunk_bits) { + pd->nbits = oldpd->nboff + next_chunk_bits; + arg->unclaimed = 0; + ASN_DEBUG("!+Parent frame %ld bits, alloting %ld [%ld..%ld] (%ld)", + (long)next_chunk_bits, (long)oldpd->moved, + (long)oldpd->nboff, (long)oldpd->nbits, + (long)(oldpd->nbits - oldpd->nboff)); + } else { + pd->nbits = oldpd->nbits; + arg->unclaimed = next_chunk_bits - avail; + ASN_DEBUG("!-Parent frame %ld, require %ld, will claim %ld", + (long)avail, (long)next_chunk_bits, + (long)arg->unclaimed); + } + pd->buffer = oldpd->buffer; + pd->nboff = oldpd->nboff; + ASN_DEBUG("Refilled pd%s old%s", + asn_bit_data_string(pd), asn_bit_data_string(oldpd)); + return 0; +} + +static int +per_skip_bits(asn_per_data_t *pd, int skip_nbits) { + int hasNonZeroBits = 0; + while(skip_nbits > 0) { + int skip; + + /* per_get_few_bits() is more efficient when nbits <= 24 */ + if(skip_nbits < 24) + skip = skip_nbits; + else + skip = 24; + skip_nbits -= skip; + + switch(per_get_few_bits(pd, skip)) { + case -1: return -1; /* Starving */ + case 0: continue; /* Skipped empty space */ + default: hasNonZeroBits = 1; continue; + } + } + return hasNonZeroBits; +} diff --git a/Vendor/asn1/include/per_opentype.h b/Vendor/asn1/include/per_opentype.h new file mode 100644 index 0000000..7e7dc61 --- /dev/null +++ b/Vendor/asn1/include/per_opentype.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2007-2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _PER_OPENTYPE_H_ +#define _PER_OPENTYPE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +asn_dec_rval_t uper_open_type_get(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, + const asn_per_constraints_t *constraints, + void **sptr, asn_per_data_t *pd); + +int uper_open_type_skip(const asn_codec_ctx_t *opt_codec_ctx, + asn_per_data_t *pd); + +/* + * X.691 (2015/08), #11.2 + * Returns -1 if error is encountered. 0 if all OK. + */ +int uper_open_type_put(const asn_TYPE_descriptor_t *td, + const asn_per_constraints_t *constraints, + const void *sptr, asn_per_outp_t *po); + +#ifdef __cplusplus +} +#endif + +#endif /* _PER_OPENTYPE_H_ */ diff --git a/Vendor/asn1/include/per_support.c b/Vendor/asn1/include/per_support.c new file mode 100644 index 0000000..8f4d460 --- /dev/null +++ b/Vendor/asn1/include/per_support.c @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2005-2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include + +/* + * X.691-201508 #10.9 General rules for encoding a length determinant. + * Get the optionally constrained length "n" from the stream. + */ +ssize_t +uper_get_length(asn_per_data_t *pd, int ebits, size_t lower_bound, + int *repeat) { + ssize_t value; + + *repeat = 0; + + /* #11.9.4.1 Encoding if constrained (according to effective bits) */ + if(ebits >= 0 && ebits <= 16) { + value = per_get_few_bits(pd, ebits); + if(value >= 0) value += lower_bound; + return value; + } + + value = per_get_few_bits(pd, 8); + if((value & 0x80) == 0) { /* #11.9.3.6 */ + return (value & 0x7F); + } else if((value & 0x40) == 0) { /* #11.9.3.7 */ + /* bit 8 ... set to 1 and bit 7 ... set to zero */ + value = ((value & 0x3f) << 8) | per_get_few_bits(pd, 8); + return value; /* potential -1 from per_get_few_bits passes through. */ + } else if(value < 0) { + ASN_DEBUG("END of stream reached for PER"); + return -1; + } + value &= 0x3f; /* this is "m" from X.691, #11.9.3.8 */ + if(value < 1 || value > 4) { + return -1; /* Prohibited by #11.9.3.8 */ + } + *repeat = 1; + return (16384 * value); +} + +/* + * Get the normally small length "n". + * This procedure used to decode length of extensions bit-maps + * for SET and SEQUENCE types. + */ +ssize_t +uper_get_nslength(asn_per_data_t *pd) { + ssize_t length; + + ASN_DEBUG("Getting normally small length"); + + if(per_get_few_bits(pd, 1) == 0) { + length = per_get_few_bits(pd, 6) + 1; + if(length <= 0) return -1; + ASN_DEBUG("l=%d", (int)length); + return length; + } else { + int repeat; + length = uper_get_length(pd, -1, 0, &repeat); + if(length >= 0 && !repeat) return length; + return -1; /* Error, or do not support >16K extensions */ + } +} + +/* + * Get the normally small non-negative whole number. + * X.691, #10.6 + */ +ssize_t +uper_get_nsnnwn(asn_per_data_t *pd) { + ssize_t value; + + value = per_get_few_bits(pd, 7); + if(value & 64) { /* implicit (value < 0) */ + value &= 63; + value <<= 2; + value |= per_get_few_bits(pd, 2); + if(value & 128) /* implicit (value < 0) */ + return -1; + if(value == 0) + return 0; + if(value >= 3) + return -1; + value = per_get_few_bits(pd, 8 * value); + return value; + } + + return value; +} + +/* + * X.691-11/2008, #11.6 + * Encoding of a normally small non-negative whole number + */ +int +uper_put_nsnnwn(asn_per_outp_t *po, int n) { + int bytes; + + if(n <= 63) { + if(n < 0) return -1; + return per_put_few_bits(po, n, 7); + } + if(n < 256) + bytes = 1; + else if(n < 65536) + bytes = 2; + else if(n < 256 * 65536) + bytes = 3; + else + return -1; /* This is not a "normally small" value */ + if(per_put_few_bits(po, bytes, 8)) + return -1; + + return per_put_few_bits(po, n, 8 * bytes); +} + + +/* X.691-2008/11, #11.5.6 -> #11.3 */ +int uper_get_constrained_whole_number(asn_per_data_t *pd, unsigned long *out_value, int nbits) { + unsigned long lhalf; /* Lower half of the number*/ + long half; + + if(nbits <= 31) { + half = per_get_few_bits(pd, nbits); + if(half < 0) return -1; + *out_value = half; + return 0; + } + + if((size_t)nbits > 8 * sizeof(*out_value)) + return -1; /* RANGE */ + + half = per_get_few_bits(pd, 31); + if(half < 0) return -1; + + if(uper_get_constrained_whole_number(pd, &lhalf, nbits - 31)) + return -1; + + *out_value = ((unsigned long)half << (nbits - 31)) | lhalf; + return 0; +} + + +/* X.691-2008/11, #11.5.6 -> #11.3 */ +int +uper_put_constrained_whole_number_u(asn_per_outp_t *po, unsigned long v, + int nbits) { + if(nbits <= 31) { + return per_put_few_bits(po, v, nbits); + } else { + /* Put higher portion first, followed by lower 31-bit */ + if(uper_put_constrained_whole_number_u(po, v >> 31, nbits - 31)) + return -1; + return per_put_few_bits(po, v, 31); + } +} + +/* + * X.691 (08/2015) #11.9 "General rules for encoding a length determinant" + * Put the length "n" (or part of it) into the stream. + */ +ssize_t +uper_put_length(asn_per_outp_t *po, size_t length, int *need_eom) { + int dummy = 0; + if(!need_eom) need_eom = &dummy; + + if(length <= 127) { /* #11.9.3.6 */ + *need_eom = 0; + return per_put_few_bits(po, length, 8) + ? -1 : (ssize_t)length; + } else if(length < 16384) { /* #10.9.3.7 */ + *need_eom = 0; + return per_put_few_bits(po, length|0x8000, 16) + ? -1 : (ssize_t)length; + } + + *need_eom = 0 == (length & 16383); + length >>= 14; + if(length > 4) { + *need_eom = 0; + length = 4; + } + + return per_put_few_bits(po, 0xC0 | length, 8) + ? -1 : (ssize_t)(length << 14); + +} + + +/* + * Put the normally small length "n" into the stream. + * This procedure used to encode length of extensions bit-maps + * for SET and SEQUENCE types. + */ +int +uper_put_nslength(asn_per_outp_t *po, size_t length) { + if(length <= 64) { + /* #11.9.3.4 */ + if(length == 0) return -1; + return per_put_few_bits(po, length - 1, 7) ? -1 : 0; + } else { + int need_eom = 0; + if(uper_put_length(po, length, &need_eom) != (ssize_t)length + || need_eom) { + /* This might happen in case of >16K extensions */ + return -1; + } + } + + return 0; +} + +static int +per__long_range(long lb, long ub, unsigned long *range_r) { + unsigned long bounds_range; + if((ub < 0) == (lb < 0)) { + bounds_range = ub - lb; + } else if(lb < 0) { + assert(ub >= 0); + bounds_range = 1 + ((unsigned long)ub + (unsigned long)-(lb + 1)); + } else { + assert(!"Unreachable"); + return -1; + } + *range_r = bounds_range; + return 0; +} + +int +per_long_range_rebase(long v, long lb, long ub, unsigned long *output) { + unsigned long range; + + assert(lb <= ub); + + if(v < lb || v > ub || per__long_range(lb, ub, &range) < 0) { + /* Range error. */ + return -1; + } + + /* + * Fundamentally what we're doing is returning (v-lb). + * However, this triggers undefined behavior when the word width + * of signed (v) is the same as the size of unsigned (*output). + * In practice, it triggers the UndefinedSanitizer. Therefore we shall + * compute the ranges accurately to avoid C's undefined behavior. + */ + if((v < 0) == (lb < 0)) { + *output = v-lb; + return 0; + } else if(v < 0) { + unsigned long rebased = 1 + (unsigned long)-(v+1) + (unsigned long)lb; + assert(rebased <= range); /* By construction */ + *output = rebased; + return 0; + } else if(lb < 0) { + unsigned long rebased = 1 + (unsigned long)-(lb+1) + (unsigned long)v; + assert(rebased <= range); /* By construction */ + *output = rebased; + return 0; + } else { + assert(!"Unreachable"); + return -1; + } +} + +int +per_long_range_unrebase(unsigned long inp, long lb, long ub, long *outp) { + unsigned long range; + + if(per__long_range(lb, ub, &range) != 0) { + return -1; + } + + if(inp > range) { + /* + * We can encode something in the given number of bits that technically + * exceeds the range. This is an avenue for security errors, + * so we don't allow that. + */ + return -1; + } + + if(inp <= LONG_MAX) { + *outp = (long)inp + lb; + } else { + *outp = (lb + LONG_MAX + 1) + (long)((inp - LONG_MAX) - 1); + } + + return 0; +} diff --git a/Vendor/asn1/include/per_support.h b/Vendor/asn1/include/per_support.h new file mode 100644 index 0000000..3e905a8 --- /dev/null +++ b/Vendor/asn1/include/per_support.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2005-2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _PER_SUPPORT_H_ +#define _PER_SUPPORT_H_ + +#include /* Platform-specific types */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Pre-computed PER constraints. + */ +typedef struct asn_per_constraint_s { + enum asn_per_constraint_flags { + APC_UNCONSTRAINED = 0x0, /* No PER visible constraints */ + APC_SEMI_CONSTRAINED = 0x1, /* Constrained at "lb" */ + APC_CONSTRAINED = 0x2, /* Fully constrained */ + APC_EXTENSIBLE = 0x4 /* May have extension */ + } flags; + int range_bits; /* Full number of bits in the range */ + int effective_bits; /* Effective bits */ + long lower_bound; /* "lb" value */ + long upper_bound; /* "ub" value */ +} asn_per_constraint_t; +typedef struct asn_per_constraints_s { + asn_per_constraint_t value; + asn_per_constraint_t size; + int (*value2code)(unsigned int value); + int (*code2value)(unsigned int code); +} asn_per_constraints_t; + +/* Temporary compatibility layer. Will get removed. */ +typedef struct asn_bit_data_s asn_per_data_t; +#define per_get_few_bits(data, bits) asn_get_few_bits(data, bits) +#define per_get_undo(data, bits) asn_get_undo(data, bits) +#define per_get_many_bits(data, dst, align, bits) \ + asn_get_many_bits(data, dst, align, bits) + +/* + * X.691 (08/2015) #11.9 "General rules for encoding a length determinant" + * Get the length "n" from the Unaligned PER stream. + */ +ssize_t uper_get_length(asn_per_data_t *pd, int effective_bound_bits, + size_t lower_bound, int *repeat); + +/* + * Get the normally small length "n". + */ +ssize_t uper_get_nslength(asn_per_data_t *pd); + +/* + * Get the normally small non-negative whole number. + */ +ssize_t uper_get_nsnnwn(asn_per_data_t *pd); + +/* X.691-2008/11, #11.5.6 */ +int uper_get_constrained_whole_number(asn_per_data_t *pd, unsigned long *v, int nbits); + + +/* Temporary compatibility layer. Will get removed. */ +typedef struct asn_bit_outp_s asn_per_outp_t; +#define per_put_few_bits(out, bits, obits) asn_put_few_bits(out, bits, obits) +#define per_put_many_bits(out, src, nbits) asn_put_many_bits(out, src, nbits) +#define per_put_aligned_flush(out) asn_put_aligned_flush(out) + + +/* + * Rebase the given value as an offset into the range specified by the + * lower bound (lb) and upper bound (ub). + * RETURN VALUES: + * -1: Conversion failed due to range problems. + * 0: Conversion was successful. + */ +int per_long_range_rebase(long v, long lb, long ub, unsigned long *output); +/* The inverse operation: restores the value by the offset and its bounds. */ +int per_long_range_unrebase(unsigned long inp, long lb, long ub, long *outp); + +/* X.691-2008/11, #11.5 */ +int uper_put_constrained_whole_number_u(asn_per_outp_t *po, unsigned long v, int nbits); + +/* + * X.691 (08/2015) #11.9 "General rules for encoding a length determinant" + * Put the length "whole_length" to the Unaligned PER stream. + * If (opt_need_eom) is given, it will be set to 1 if final 0-length is needed. + * In that case, invoke uper_put_length(po, 0, 0) after encoding the last block. + * This function returns the number of units which may be flushed + * in the next units saving iteration. + */ +ssize_t uper_put_length(asn_per_outp_t *po, size_t whole_length, + int *opt_need_eom); + +/* + * Put the normally small length "n" to the Unaligned PER stream. + * Returns 0 or -1. + */ +int uper_put_nslength(asn_per_outp_t *po, size_t length); + +/* + * Put the normally small non-negative whole number. + */ +int uper_put_nsnnwn(asn_per_outp_t *po, int n); + +#ifdef __cplusplus +} +#endif + +#endif /* _PER_SUPPORT_H_ */ diff --git a/Vendor/asn1/include/xer_decoder.c b/Vendor/asn1/include/xer_decoder.c new file mode 100644 index 0000000..5b87703 --- /dev/null +++ b/Vendor/asn1/include/xer_decoder.c @@ -0,0 +1,369 @@ +/* + * Copyright (c) 2004-2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include /* XER/XML parsing support */ + + +/* + * Decode the XER encoding of a given type. + */ +asn_dec_rval_t +xer_decode(const asn_codec_ctx_t *opt_codec_ctx, + const asn_TYPE_descriptor_t *td, void **struct_ptr, + const void *buffer, size_t size) { + asn_codec_ctx_t s_codec_ctx; + + /* + * Stack checker requires that the codec context + * must be allocated on the stack. + */ + if(opt_codec_ctx) { + if(opt_codec_ctx->max_stack_size) { + s_codec_ctx = *opt_codec_ctx; + opt_codec_ctx = &s_codec_ctx; + } + } else { + /* If context is not given, be security-conscious anyway */ + memset(&s_codec_ctx, 0, sizeof(s_codec_ctx)); + s_codec_ctx.max_stack_size = ASN__DEFAULT_STACK_MAX; + opt_codec_ctx = &s_codec_ctx; + } + + /* + * Invoke type-specific decoder. + */ + return td->op->xer_decoder(opt_codec_ctx, td, struct_ptr, 0, buffer, size); +} + + + +struct xer__cb_arg { + pxml_chunk_type_e chunk_type; + size_t chunk_size; + const void *chunk_buf; + int callback_not_invoked; +}; + +static int +xer__token_cb(pxml_chunk_type_e type, const void *_chunk_data, size_t _chunk_size, void *key) { + struct xer__cb_arg *arg = (struct xer__cb_arg *)key; + arg->chunk_type = type; + arg->chunk_size = _chunk_size; + arg->chunk_buf = _chunk_data; + arg->callback_not_invoked = 0; + return -1; /* Terminate the XML parsing */ +} + +/* + * Fetch the next token from the XER/XML stream. + */ +ssize_t +xer_next_token(int *stateContext, const void *buffer, size_t size, pxer_chunk_type_e *ch_type) { + struct xer__cb_arg arg; + int new_stateContext = *stateContext; + ssize_t ret; + + arg.callback_not_invoked = 1; + ret = pxml_parse(&new_stateContext, buffer, size, xer__token_cb, &arg); + if(ret < 0) return -1; + if(arg.callback_not_invoked) { + assert(ret == 0); /* No data was consumed */ + *ch_type = PXER_WMORE; + return 0; /* Try again with more data */ + } else { + assert(arg.chunk_size); + assert(arg.chunk_buf == buffer); + } + + /* + * Translate the XML chunk types into more convenient ones. + */ + switch(arg.chunk_type) { + case PXML_TEXT: + *ch_type = PXER_TEXT; + break; + case PXML_TAG: + *ch_type = PXER_WMORE; + return 0; /* Want more */ + case PXML_TAG_END: + *ch_type = PXER_TAG; + break; + case PXML_COMMENT: + case PXML_COMMENT_END: + *ch_type = PXER_COMMENT; + break; + } + + *stateContext = new_stateContext; + return arg.chunk_size; +} + +#define CSLASH 0x2f /* '/' */ +#define LANGLE 0x3c /* '<' */ +#define RANGLE 0x3e /* '>' */ + +xer_check_tag_e +xer_check_tag(const void *buf_ptr, int size, const char *need_tag) { + const char *buf = (const char *)buf_ptr; + const char *end; + xer_check_tag_e ct = XCT_OPENING; + + if(size < 2 || buf[0] != LANGLE || buf[size-1] != RANGLE) { + if(size >= 2) + ASN_DEBUG("Broken XML tag: \"%c...%c\"", + buf[0], buf[size - 1]); + return XCT_BROKEN; + } + + /* + * Determine the tag class. + */ + if(buf[1] == CSLASH) { + buf += 2; /* advance past "" */ + ct = XCT_CLOSING; + if(size > 0 && buf[size-1] == CSLASH) + return XCT_BROKEN; /* */ + } else { + buf++; /* advance past "<" */ + size -= 2; /* strip "<" and ">" */ + if(size > 0 && buf[size-1] == CSLASH) { + ct = XCT_BOTH; + size--; /* One more, for "/" */ + } + } + + /* Sometimes we don't care about the tag */ + if(!need_tag || !*need_tag) + return (xer_check_tag_e)(XCT__UNK__MASK | ct); + + /* + * Determine the tag name. + */ + for(end = buf + size; buf < end; buf++, need_tag++) { + int b = *buf, n = *need_tag; + if(b != n) { + if(n == 0) { + switch(b) { + case 0x09: case 0x0a: case 0x0c: case 0x0d: + case 0x20: + /* "": whitespace is normal */ + return ct; + } + } + return (xer_check_tag_e)(XCT__UNK__MASK | ct); + } + if(b == 0) + return XCT_BROKEN; /* Embedded 0 in buf?! */ + } + if(*need_tag) + return (xer_check_tag_e)(XCT__UNK__MASK | ct); + + return ct; +} + + +#undef ADVANCE +#define ADVANCE(num_bytes) do { \ + size_t num = (num_bytes); \ + buf_ptr = ((const char *)buf_ptr) + num; \ + size -= num; \ + consumed_myself += num; \ + } while(0) + +#undef RETURN +#define RETURN(_code) do { \ + rval.code = _code; \ + rval.consumed = consumed_myself; \ + if(rval.code != RC_OK) \ + ASN_DEBUG("Failed with %d", rval.code); \ + return rval; \ + } while(0) + +#define XER_GOT_BODY(chunk_buf, chunk_size, size) do { \ + ssize_t converted_size = body_receiver \ + (struct_key, chunk_buf, chunk_size, \ + (size_t)chunk_size < size); \ + if(converted_size == -1) RETURN(RC_FAIL); \ + if(converted_size == 0 \ + && size == (size_t)chunk_size) \ + RETURN(RC_WMORE); \ + chunk_size = converted_size; \ + } while(0) +#define XER_GOT_EMPTY() do { \ + if(body_receiver(struct_key, 0, 0, size > 0) == -1) \ + RETURN(RC_FAIL); \ + } while(0) + +/* + * Generalized function for decoding the primitive values. + */ +asn_dec_rval_t +xer_decode_general(const asn_codec_ctx_t *opt_codec_ctx, + asn_struct_ctx_t *ctx, /* Type decoder context */ + void *struct_key, + const char *xml_tag, /* Expected XML tag */ + const void *buf_ptr, size_t size, + int (*opt_unexpected_tag_decoder) + (void *struct_key, const void *chunk_buf, size_t chunk_size), + ssize_t (*body_receiver) + (void *struct_key, const void *chunk_buf, size_t chunk_size, + int have_more) + ) { + + asn_dec_rval_t rval; + ssize_t consumed_myself = 0; + + (void)opt_codec_ctx; + + /* + * Phases of XER/XML processing: + * Phase 0: Check that the opening tag matches our expectations. + * Phase 1: Processing body and reacting on closing tag. + */ + if(ctx->phase > 1) RETURN(RC_FAIL); + for(;;) { + pxer_chunk_type_e ch_type; /* XER chunk type */ + ssize_t ch_size; /* Chunk size */ + xer_check_tag_e tcv; /* Tag check value */ + + /* + * Get the next part of the XML stream. + */ + ch_size = xer_next_token(&ctx->context, buf_ptr, size, + &ch_type); + if(ch_size == -1) { + RETURN(RC_FAIL); + } else { + switch(ch_type) { + case PXER_WMORE: + RETURN(RC_WMORE); + case PXER_COMMENT: /* Got XML comment */ + ADVANCE(ch_size); /* Skip silently */ + continue; + case PXER_TEXT: + if(ctx->phase == 0) { + /* + * We have to ignore whitespace here, + * but in order to be forward compatible + * with EXTENDED-XER (EMBED-VALUES, #25) + * any text is just ignored here. + */ + } else { + XER_GOT_BODY(buf_ptr, ch_size, size); + } + ADVANCE(ch_size); + continue; + case PXER_TAG: + break; /* Check the rest down there */ + } + } + + assert(ch_type == PXER_TAG && size); + + tcv = xer_check_tag(buf_ptr, ch_size, xml_tag); + /* + * Phase 0: + * Expecting the opening tag + * for the type being processed. + * Phase 1: + * Waiting for the closing XML tag. + */ + switch(tcv) { + case XCT_BOTH: + if(ctx->phase) break; + /* Finished decoding of an empty element */ + XER_GOT_EMPTY(); + ADVANCE(ch_size); + ctx->phase = 2; /* Phase out */ + RETURN(RC_OK); + case XCT_OPENING: + if(ctx->phase) break; + ADVANCE(ch_size); + ctx->phase = 1; /* Processing body phase */ + continue; + case XCT_CLOSING: + if(!ctx->phase) break; + ADVANCE(ch_size); + ctx->phase = 2; /* Phase out */ + RETURN(RC_OK); + case XCT_UNKNOWN_BO: + /* + * Certain tags in the body may be expected. + */ + if(opt_unexpected_tag_decoder + && opt_unexpected_tag_decoder(struct_key, + buf_ptr, ch_size) >= 0) { + /* Tag's processed fine */ + ADVANCE(ch_size); + if(!ctx->phase) { + /* We are not expecting + * the closing tag anymore. */ + ctx->phase = 2; /* Phase out */ + RETURN(RC_OK); + } + continue; + } + /* Fall through */ + default: + break; /* Unexpected tag */ + } + + ASN_DEBUG("Unexpected XML tag (expected \"%s\")", xml_tag); + break; /* Dark and mysterious things have just happened */ + } + + RETURN(RC_FAIL); +} + + +size_t +xer_whitespace_span(const void *chunk_buf, size_t chunk_size) { + const char *p = (const char *)chunk_buf; + const char *pend = p + chunk_size; + + for(; p < pend; p++) { + switch(*p) { + /* X.693, #8.1.4 + * HORISONTAL TAB (9) + * LINE FEED (10) + * CARRIAGE RETURN (13) + * SPACE (32) + */ + case 0x09: case 0x0a: case 0x0d: case 0x20: + continue; + default: + break; + } + break; + } + return (p - (const char *)chunk_buf); +} + +/* + * This is a vastly simplified, non-validating XML tree skipper. + */ +int +xer_skip_unknown(xer_check_tag_e tcv, ber_tlv_len_t *depth) { + assert(*depth > 0); + switch(tcv) { + case XCT_BOTH: + case XCT_UNKNOWN_BO: + /* These negate each other. */ + return 0; + case XCT_OPENING: + case XCT_UNKNOWN_OP: + ++(*depth); + return 0; + case XCT_CLOSING: + case XCT_UNKNOWN_CL: + if(--(*depth) == 0) + return (tcv == XCT_CLOSING) ? 2 : 1; + return 0; + default: + return -1; + } +} diff --git a/Vendor/asn1/include/xer_decoder.h b/Vendor/asn1/include/xer_decoder.h new file mode 100644 index 0000000..b951c41 --- /dev/null +++ b/Vendor/asn1/include/xer_decoder.h @@ -0,0 +1,106 @@ +/*- + * Copyright (c) 2004-2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _XER_DECODER_H_ +#define _XER_DECODER_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct asn_TYPE_descriptor_s; /* Forward declaration */ + +/* + * The XER decoder of any ASN.1 type. May be invoked by the application. + * Decodes CANONICAL-XER and BASIC-XER. + */ +asn_dec_rval_t xer_decode( + const struct asn_codec_ctx_s *opt_codec_ctx, + const struct asn_TYPE_descriptor_s *type_descriptor, + void **struct_ptr, /* Pointer to a target structure's pointer */ + const void *buffer, /* Data to be decoded */ + size_t size /* Size of data buffer */ +); + +/* + * Type of the type-specific XER decoder function. + */ +typedef asn_dec_rval_t(xer_type_decoder_f)( + const asn_codec_ctx_t *opt_codec_ctx, + const struct asn_TYPE_descriptor_s *type_descriptor, void **struct_ptr, + const char *opt_mname, /* Member name */ + const void *buf_ptr, size_t size); + +/******************************* + * INTERNALLY USEFUL FUNCTIONS * + *******************************/ + +/* + * Generalized function for decoding the primitive values. + * Used by more specialized functions, such as OCTET_STRING_decode_xer_utf8 + * and others. This function should not be used by applications, as its API + * is subject to changes. + */ +asn_dec_rval_t xer_decode_general( + const asn_codec_ctx_t *opt_codec_ctx, + asn_struct_ctx_t *ctx, /* Type decoder context */ + void *struct_key, /* Treated as opaque pointer */ + const char *xml_tag, /* Expected XML tag name */ + const void *buf_ptr, size_t size, + int (*opt_unexpected_tag_decoder)(void *struct_key, const void *chunk_buf, + size_t chunk_size), + ssize_t (*body_receiver)(void *struct_key, const void *chunk_buf, + size_t chunk_size, int have_more)); + + +/* + * Fetch the next XER (XML) token from the stream. + * The function returns the number of bytes occupied by the chunk type, + * returned in the _ch_type. The _ch_type is only set (and valid) when + * the return value is >= 0. + */ + typedef enum pxer_chunk_type { + PXER_WMORE, /* Chunk type is not clear, more data expected. */ + PXER_TAG, /* Complete XER tag */ + PXER_TEXT, /* Plain text between XER tags */ + PXER_COMMENT /* A comment, may be part of */ + } pxer_chunk_type_e; +ssize_t xer_next_token(int *stateContext, + const void *buffer, size_t size, pxer_chunk_type_e *_ch_type); + +/* + * This function checks the buffer against the tag name is expected to occur. + */ + typedef enum xer_check_tag { + XCT_BROKEN = 0, /* The tag is broken */ + XCT_OPENING = 1, /* This is the tag */ + XCT_CLOSING = 2, /* This is the tag */ + XCT_BOTH = 3, /* This is the tag */ + XCT__UNK__MASK = 4, /* Mask of everything unexpected */ + XCT_UNKNOWN_OP = 5, /* Unexpected tag */ + XCT_UNKNOWN_CL = 6, /* Unexpected tag */ + XCT_UNKNOWN_BO = 7 /* Unexpected tag */ + } xer_check_tag_e; +xer_check_tag_e xer_check_tag(const void *buf_ptr, int size, + const char *need_tag); + +/* + * Get the number of bytes consisting entirely of XER whitespace characters. + * RETURN VALUES: + * >=0: Number of whitespace characters in the string. + */ +size_t xer_whitespace_span(const void *chunk_buf, size_t chunk_size); + +/* + * Skip the series of anticipated extensions. + */ +int xer_skip_unknown(xer_check_tag_e tcv, ber_tlv_len_t *depth); + +#ifdef __cplusplus +} +#endif + +#endif /* _XER_DECODER_H_ */ diff --git a/Vendor/asn1/include/xer_encoder.c b/Vendor/asn1/include/xer_encoder.c new file mode 100644 index 0000000..dff3c44 --- /dev/null +++ b/Vendor/asn1/include/xer_encoder.c @@ -0,0 +1,237 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include + +/* + * The XER encoder of any type. May be invoked by the application. + */ +asn_enc_rval_t +xer_encode(const asn_TYPE_descriptor_t *td, const void *sptr, + enum xer_encoder_flags_e xer_flags, asn_app_consume_bytes_f *cb, + void *app_key) { + asn_enc_rval_t er = {0, 0, 0}; + asn_enc_rval_t tmper; + const char *mname; + size_t mlen; + int xcan = (xer_flags & XER_F_CANONICAL) ? 1 : 2; + + if(!td || !sptr) goto cb_failed; + + mname = td->xml_tag; + mlen = strlen(mname); + + ASN__CALLBACK3("<", 1, mname, mlen, ">", 1); + + tmper = td->op->xer_encoder(td, sptr, 1, xer_flags, cb, app_key); + if(tmper.encoded == -1) return tmper; + er.encoded += tmper.encoded; + + ASN__CALLBACK3("\n", xcan); + + ASN__ENCODED_OK(er); +cb_failed: + ASN__ENCODE_FAILED; +} + +/* + * This is a helper function for xer_fprint, which directs all incoming data + * into the provided file descriptor. + */ +static int +xer__print2fp(const void *buffer, size_t size, void *app_key) { + FILE *stream = (FILE *)app_key; + + if(fwrite(buffer, 1, size, stream) != size) + return -1; + + return 0; +} + +int +xer_fprint(FILE *stream, const asn_TYPE_descriptor_t *td, const void *sptr) { + asn_enc_rval_t er; + + if(!stream) stream = stdout; + if(!td || !sptr) + return -1; + + er = xer_encode(td, sptr, XER_F_BASIC, xer__print2fp, stream); + if(er.encoded == -1) + return -1; + + return fflush(stream); +} + +struct xer_buffer { + char *buffer; + size_t buffer_size; + size_t allocated_size; +}; + +static int +xer__buffer_append(const void *buffer, size_t size, void *app_key) { + struct xer_buffer *xb = app_key; + + while(xb->buffer_size + size + 1 > xb->allocated_size) { + size_t new_size = 2 * (xb->allocated_size ? xb->allocated_size : 64); + char *new_buf = MALLOC(new_size); + if(!new_buf) return -1; + if (xb->buffer) { + memcpy(new_buf, xb->buffer, xb->buffer_size); + } + FREEMEM(xb->buffer); + xb->buffer = new_buf; + xb->allocated_size = new_size; + } + + memcpy(xb->buffer + xb->buffer_size, buffer, size); + xb->buffer_size += size; + xb->buffer[xb->buffer_size] = '\0'; + return 0; +} + +enum xer_equivalence_e +xer_equivalent(const struct asn_TYPE_descriptor_s *td, const void *struct1, + const void *struct2, FILE *opt_debug_stream) { + struct xer_buffer xb1 = {0, 0, 0}; + struct xer_buffer xb2 = {0, 0, 0}; + asn_enc_rval_t e1, e2; + asn_dec_rval_t rval; + void *sptr = NULL; + + if(!td || !struct1 || !struct2) { + if(opt_debug_stream) { + if(!td) fprintf(opt_debug_stream, "Type descriptor missing\n"); + if(!struct1) fprintf(opt_debug_stream, "Structure 1 missing\n"); + if(!struct2) fprintf(opt_debug_stream, "Structure 2 missing\n"); + } + return XEQ_FAILURE; + } + + e1 = xer_encode(td, struct1, XER_F_BASIC, xer__buffer_append, &xb1); + if(e1.encoded == -1) { + if(opt_debug_stream) { + fprintf(stderr, "XER Encoding of %s failed\n", td->name); + } + FREEMEM(xb1.buffer); + return XEQ_ENCODE1_FAILED; + } + + e2 = xer_encode(td, struct2, XER_F_BASIC, xer__buffer_append, &xb2); + if(e2.encoded == -1) { + if(opt_debug_stream) { + fprintf(stderr, "XER Encoding of %s failed\n", td->name); + } + FREEMEM(xb1.buffer); + FREEMEM(xb2.buffer); + return XEQ_ENCODE1_FAILED; + } + + if(xb1.buffer_size != xb2.buffer_size + || memcmp(xb1.buffer, xb2.buffer, xb1.buffer_size) != 0) { + if(opt_debug_stream) { + fprintf(opt_debug_stream, + "Structures XER-encoded into different byte streams:\n=== " + "Structure 1 ===\n%s\n=== Structure 2 ===\n%s\n", + xb1.buffer, xb2.buffer); + } + FREEMEM(xb1.buffer); + FREEMEM(xb2.buffer); + return XEQ_DIFFERENT; + } else { + if(opt_debug_stream) { + fprintf(opt_debug_stream, + "Both structures encoded into the same XER byte stream " + "of size %" ASN_PRI_SIZE ":\n%s", + xb1.buffer_size, xb1.buffer); + } + } + + rval = xer_decode(NULL, td, (void **)&sptr, xb1.buffer, + xb1.buffer_size); + switch(rval.code) { + case RC_OK: + break; + case RC_WMORE: + if(opt_debug_stream) { + fprintf(opt_debug_stream, + "Structure %s XER decode unexpectedly requires " + "more data:\n%s\n", + td->name, xb1.buffer); + } + /* Fall through */ + case RC_FAIL: + default: + if(opt_debug_stream) { + fprintf(opt_debug_stream, + "Structure %s XER decoding resulted in failure.\n", + td->name); + } + ASN_STRUCT_FREE(*td, sptr); + FREEMEM(xb1.buffer); + FREEMEM(xb2.buffer); + return XEQ_DECODE_FAILED; + } + + if(rval.consumed != xb1.buffer_size + && ((rval.consumed > xb1.buffer_size) + || xer_whitespace_span(xb1.buffer + rval.consumed, + xb1.buffer_size - rval.consumed) + != (xb1.buffer_size - rval.consumed))) { + if(opt_debug_stream) { + fprintf(opt_debug_stream, + "Round-trip decode of %s required less bytes (%" ASN_PRI_SIZE ") than " + "encoded (%" ASN_PRI_SIZE ")\n", + td->name, rval.consumed, xb1.buffer_size); + } + ASN_STRUCT_FREE(*td, sptr); + FREEMEM(xb1.buffer); + FREEMEM(xb2.buffer); + return XEQ_ROUND_TRIP_FAILED; + } + + /* + * Reuse xb2 to encode newly decoded structure. + */ + FREEMEM(xb2.buffer); + memset(&xb2, 0, sizeof(xb2)); + + e2 = xer_encode(td, sptr, XER_F_BASIC, xer__buffer_append, &xb2); + if(e2.encoded == -1) { + if(opt_debug_stream) { + fprintf(stderr, "XER Encoding of round-trip decode of %s failed\n", + td->name); + } + ASN_STRUCT_FREE(*td, sptr); + FREEMEM(xb1.buffer); + FREEMEM(xb2.buffer); + return XEQ_ROUND_TRIP_FAILED; + } + + ASN_STRUCT_FREE(*td, sptr); + sptr = 0; + + if(xb1.buffer_size != xb2.buffer_size + || memcmp(xb1.buffer, xb2.buffer, xb1.buffer_size) != 0) { + if(opt_debug_stream) { + fprintf(opt_debug_stream, + "XER Encoding of round-trip decode of %s resulted in " + "different byte stream:\n" + "=== Original ===\n%s\n" + "=== Round-tripped ===\n%s\n", + xb1.buffer, xb2.buffer, td->name); + } + FREEMEM(xb1.buffer); + FREEMEM(xb2.buffer); + return XEQ_ROUND_TRIP_FAILED; + } + + FREEMEM(xb1.buffer); + FREEMEM(xb2.buffer); + return XEQ_SUCCESS; +} + diff --git a/Vendor/asn1/include/xer_encoder.h b/Vendor/asn1/include/xer_encoder.h new file mode 100644 index 0000000..9d75922 --- /dev/null +++ b/Vendor/asn1/include/xer_encoder.h @@ -0,0 +1,83 @@ +/*- + * Copyright (c) 2004-2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _XER_ENCODER_H_ +#define _XER_ENCODER_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct asn_TYPE_descriptor_s; /* Forward declaration */ + +/* Flags used by the xer_encode() and (*xer_type_encoder_f), defined below */ +enum xer_encoder_flags_e { + /* Mode of encoding */ + XER_F_BASIC = 0x01, /* BASIC-XER (pretty-printing) */ + XER_F_CANONICAL = 0x02 /* Canonical XER (strict rules) */ +}; + +/* + * The XER encoder of any type. May be invoked by the application. + * Produces CANONICAL-XER and BASIC-XER depending on the (xer_flags). + */ +asn_enc_rval_t xer_encode(const struct asn_TYPE_descriptor_s *type_descriptor, + const void *struct_ptr, /* Structure to be encoded */ + enum xer_encoder_flags_e xer_flags, + asn_app_consume_bytes_f *consume_bytes_cb, + void *app_key /* Arbitrary callback argument */ +); + +/* + * The variant of the above function which dumps the BASIC-XER (XER_F_BASIC) + * output into the chosen file pointer. + * RETURN VALUES: + * 0: The structure is printed. + * -1: Problem printing the structure. + * WARNING: No sensible errno value is returned. + */ +int xer_fprint(FILE *stream, const struct asn_TYPE_descriptor_s *td, + const void *struct_ptr); + +/* + * A helper function that uses XER encoding/decoding to verify that: + * - Both structures encode into the same BASIC XER. + * - Both resulting XER byte streams can be decoded back. + * - Both decoded structures encode into the same BASIC XER (round-trip). + * All of this verifies equivalence between structures and a round-trip. + * ARGUMENTS: + * (opt_debug_stream) - If specified, prints ongoing details. + */ +enum xer_equivalence_e { + XEQ_SUCCESS, /* The only completely positive return value */ + XEQ_FAILURE, /* General failure */ + XEQ_ENCODE1_FAILED, /* First sructure XER encoding failed */ + XEQ_ENCODE2_FAILED, /* Second structure XER encoding failed */ + XEQ_DIFFERENT, /* Structures encoded into different XER */ + XEQ_DECODE_FAILED, /* Decode of the XER data failed */ + XEQ_ROUND_TRIP_FAILED /* Bad round-trip */ +}; +enum xer_equivalence_e xer_equivalent( + const struct asn_TYPE_descriptor_s *type_descriptor, const void *struct1, + const void *struct2, FILE *opt_debug_stream); + +/* + * Type of the generic XER encoder. + */ +typedef asn_enc_rval_t(xer_type_encoder_f)( + const struct asn_TYPE_descriptor_s *type_descriptor, + const void *struct_ptr, /* Structure to be encoded */ + int ilevel, /* Level of indentation */ + enum xer_encoder_flags_e xer_flags, + asn_app_consume_bytes_f *consume_bytes_cb, /* Callback */ + void *app_key /* Arbitrary callback argument */ +); + +#ifdef __cplusplus +} +#endif + +#endif /* _XER_ENCODER_H_ */ diff --git a/Vendor/asn1/include/xer_support.c b/Vendor/asn1/include/xer_support.c new file mode 100644 index 0000000..36b4bfb --- /dev/null +++ b/Vendor/asn1/include/xer_support.c @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2003, 2004 X/IO Labs, xiolabs.com. + * Copyright (c) 2003, 2004, 2005 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include + +/* Parser states */ +typedef enum { + ST_TEXT, + ST_TAG_START, + ST_TAG_BODY, + ST_TAG_QUOTE_WAIT, + ST_TAG_QUOTED_STRING, + ST_TAG_UNQUOTED_STRING, + ST_COMMENT_WAIT_DASH1, /* ""[0] */ + ST_COMMENT_CLO_RT /* "-->"[1] */ +} pstate_e; + +static const int +_charclass[256] = { + 0,0,0,0,0,0,0,0, 0,1,1,0,1,1,0,0, + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, + 1,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2, 2,2,0,0,0,0,0,0, /* 01234567 89 */ + 0,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3, /* ABCDEFG HIJKLMNO */ + 3,3,3,3,3,3,3,3, 3,3,3,0,0,0,0,0, /* PQRSTUVW XYZ */ + 0,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3, /* abcdefg hijklmno */ + 3,3,3,3,3,3,3,3, 3,3,3,0,0,0,0,0 /* pqrstuvw xyz */ +}; +#define WHITESPACE(c) (_charclass[(unsigned char)(c)] == 1) +#define ALNUM(c) (_charclass[(unsigned char)(c)] >= 2) +#define ALPHA(c) (_charclass[(unsigned char)(c)] == 3) + +/* Aliases for characters, ASCII/UTF-8 */ +#define EXCLAM 0x21 /* '!' */ +#define CQUOTE 0x22 /* '"' */ +#define CDASH 0x2d /* '-' */ +#define CSLASH 0x2f /* '/' */ +#define LANGLE 0x3c /* '<' */ +#define CEQUAL 0x3d /* '=' */ +#define RANGLE 0x3e /* '>' */ +#define CQUEST 0x3f /* '?' */ + +/* Invoke token callback */ +#define TOKEN_CB_CALL(type, _ns, _current_too, _final) do { \ + int _ret; \ + pstate_e ns = _ns; \ + ssize_t _sz = (p - chunk_start) + _current_too; \ + if (!_sz) { \ + /* Shortcut */ \ + state = _ns; \ + break; \ + } \ + _ret = cb(type, chunk_start, _sz, key); \ + if(_ret < _sz) { \ + if(_current_too && _ret == -1) \ + state = ns; \ + goto finish; \ + } \ + chunk_start = p + _current_too; \ + state = ns; \ + } while(0) + +#define TOKEN_CB(_type, _ns, _current_too) \ + TOKEN_CB_CALL(_type, _ns, _current_too, 0) + +#define PXML_TAG_FINAL_CHUNK_TYPE PXML_TAG_END +#define PXML_COMMENT_FINAL_CHUNK_TYPE PXML_COMMENT_END + +#define TOKEN_CB_FINAL(_type, _ns, _current_too) \ + TOKEN_CB_CALL( _type ## _FINAL_CHUNK_TYPE , _ns, _current_too, 1) + +/* + * Parser itself + */ +ssize_t pxml_parse(int *stateContext, const void *xmlbuf, size_t size, pxml_callback_f *cb, void *key) { + pstate_e state = (pstate_e)*stateContext; + const char *chunk_start = (const char *)xmlbuf; + const char *p = chunk_start; + const char *end = p + size; + + for(; p < end; p++) { + int C = *(const unsigned char *)p; + switch(state) { + case ST_TEXT: + /* + * Initial state: we're in the middle of some text, + * or just have started. + */ + if (C == LANGLE) + /* We're now in the tag, probably */ + TOKEN_CB(PXML_TEXT, ST_TAG_START, 0); + break; + case ST_TAG_START: + if (ALPHA(C) || (C == CSLASH)) + state = ST_TAG_BODY; + else if (C == EXCLAM) + state = ST_COMMENT_WAIT_DASH1; + else + /* + * Not characters and not whitespace. + * Must be something like "3 < 4". + */ + TOKEN_CB(PXML_TEXT, ST_TEXT, 1);/* Flush as data */ + break; + case ST_TAG_BODY: + switch(C) { + case RANGLE: + /* End of the tag */ + TOKEN_CB_FINAL(PXML_TAG, ST_TEXT, 1); + break; + case LANGLE: + /* + * The previous tag wasn't completed, but still + * recognized as valid. (Mozilla-compatible) + */ + TOKEN_CB_FINAL(PXML_TAG, ST_TAG_START, 0); + break; + case CEQUAL: + state = ST_TAG_QUOTE_WAIT; + break; + } + break; + case ST_TAG_QUOTE_WAIT: + /* + * State after the equal sign ("=") in the tag. + */ + switch(C) { + case CQUOTE: + state = ST_TAG_QUOTED_STRING; + break; + case RANGLE: + /* End of the tag */ + TOKEN_CB_FINAL(PXML_TAG, ST_TEXT, 1); + break; + default: + if(!WHITESPACE(C)) + /* Unquoted string value */ + state = ST_TAG_UNQUOTED_STRING; + } + break; + case ST_TAG_QUOTED_STRING: + /* + * Tag attribute's string value in quotes. + */ + if(C == CQUOTE) { + /* Return back to the tag state */ + state = ST_TAG_BODY; + } + break; + case ST_TAG_UNQUOTED_STRING: + if(C == RANGLE) { + /* End of the tag */ + TOKEN_CB_FINAL(PXML_TAG, ST_TEXT, 1); + } else if(WHITESPACE(C)) { + /* Return back to the tag state */ + state = ST_TAG_BODY; + } + break; + case ST_COMMENT_WAIT_DASH1: + if(C == CDASH) { + state = ST_COMMENT_WAIT_DASH2; + } else { + /* Some ordinary tag. */ + state = ST_TAG_BODY; + } + break; + case ST_COMMENT_WAIT_DASH2: + if(C == CDASH) { + /* Seen "<--" */ + state = ST_COMMENT; + } else { + /* Some ordinary tag */ + state = ST_TAG_BODY; + } + break; + case ST_COMMENT: + if(C == CDASH) { + state = ST_COMMENT_CLO_DASH2; + } + break; + case ST_COMMENT_CLO_DASH2: + if(C == CDASH) { + state = ST_COMMENT_CLO_RT; + } else { + /* This is not an end of a comment */ + state = ST_COMMENT; + } + break; + case ST_COMMENT_CLO_RT: + if(C == RANGLE) { + TOKEN_CB_FINAL(PXML_COMMENT, ST_TEXT, 1); + } else if(C == CDASH) { + /* Maintain current state, still waiting for '>' */ + } else { + state = ST_COMMENT; + } + break; + } /* switch(*ptr) */ + } /* for() */ + + /* + * Flush the partially processed chunk, state permitting. + */ + if(p - chunk_start) { + switch (state) { + case ST_COMMENT: + TOKEN_CB(PXML_COMMENT, state, 0); + break; + case ST_TEXT: + TOKEN_CB(PXML_TEXT, state, 0); + break; + default: break; /* a no-op */ + } + } + +finish: + *stateContext = (int)state; + return chunk_start - (const char *)xmlbuf; +} + diff --git a/Vendor/asn1/include/xer_support.h b/Vendor/asn1/include/xer_support.h new file mode 100644 index 0000000..c3a36e7 --- /dev/null +++ b/Vendor/asn1/include/xer_support.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2003, 2004 X/IO Labs, xiolabs.com. + * Copyright (c) 2003-2017 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _XER_SUPPORT_H_ +#define _XER_SUPPORT_H_ + +#include /* Platform-specific types */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Types of data transferred to the application. + */ +typedef enum { + PXML_TEXT, /* Plain text between XML tags. */ + PXML_TAG, /* A tag, starting with '<'. */ + PXML_COMMENT, /* An XML comment, including "". */ + /* + * The following chunk types are reported if the chunk + * terminates the specified XML element. + */ + PXML_TAG_END, /* Tag ended */ + PXML_COMMENT_END /* Comment ended */ +} pxml_chunk_type_e; + +/* + * Callback function that is called by the parser when parsed data is + * available. The _opaque is the pointer to a field containing opaque user + * data specified in pxml_create() call. The chunk type is _type and the text + * data is the piece of buffer identified by _bufid (as supplied to + * pxml_feed() call) starting at offset _offset and of _size bytes size. + * The chunk is NOT '\0'-terminated. + */ +typedef int (pxml_callback_f)(pxml_chunk_type_e _type, + const void *_chunk_data, size_t _chunk_size, void *_key); + +/* + * Parse the given buffer as it were a chunk of XML data. + * Invoke the specified callback each time the meaninful data is found. + * This function returns number of bytes consumed from the bufer. + * It will always be lesser than or equal to the specified _size. + * The next invocation of this function must account the difference. + */ +ssize_t pxml_parse(int *_stateContext, const void *_buf, size_t _size, + pxml_callback_f *cb, void *_key); + +#ifdef __cplusplus +} +#endif + +#endif /* _XER_SUPPORT_H_ */ diff --git a/Vendor/sha1/README.rst b/Vendor/sha1/README.rst new file mode 100755 index 0000000..05b78a2 --- /dev/null +++ b/Vendor/sha1/README.rst @@ -0,0 +1,83 @@ +NAME + SHA1Init, SHA1Update, SHA1Final, SHA1Transform + +SYNOPSIS + #include + + #include + + void SHA1Transform( + uint32_t state[5], + const unsigned char buffer[64]); + + void SHA1Init( + SHA1_CTX * context); + + void SHA1Update( + SHA1_CTX * context, + const unsigned char *data, + uint32_t len); + + void SHA1Final( + unsigned char digest[20], + SHA1_CTX * context); + +DESCRIPTION + The SHA1 functions implement the NIST Secure Hash Algorithm (SHA-1), FIPS + PUB 180-1. SHA-1 is used to generate a condensed representation of a + message called a message digest. The algorithm takes a message less than + 2^64 bits as input and produces a 160-bit digest suitable for use as a + digital signature. + + The SHA1Init() function initializes a SHA1_CTX context for use with + SHA1Update(), and SHA1Final(). The SHA1Update() function adds data of + length len to the SHA1_CTX specified by context. SHA1Final() is called + when all data has been added via SHA1Update() and stores a message digest + in the digest parameter. When a null pointer is passed to SHA1Final() as + first argument only the final padding will be applied and the current + context can still be used with SHA1Update(). + + The SHA1Transform() function is used by SHA1Update() to hash 512-bit + blocks and forms the core of the algorithm. Most programs should use the + interface provided by SHA1Init(), SHA1Update() and SHA1Final() instead of + calling SHA1Transform() directly. + +EXAMPLES + The follow code fragment will calculate the digest for the string "abc" + which is ``0xa9993e36476816aba3e25717850c26c9cd0d89d''. + + SHA1_CTX sha; + uint8_t results[20]; + char *buf; + int n; + + buf = "abc"; + n = strlen(buf); + SHA1Init(&sha); + SHA1Update(&sha, (uint8_t *)buf, n); + SHA1Final(results, &sha); + + /* Print the digest as one long hex value */ + printf("0x"); + for (n = 0; n < 20; n++) + printf("%02x", results[n]); + putchar('\n'); + + Alternately, the helper functions could be used in the following way: + + SHA1_CTX sha; + uint8_t output[41]; + char *buf = "abc"; + + printf("0x%s", SHA1Data(buf, strlen(buf), output)); + +AUTHORS + This implementation of SHA-1 was written by Steve Reid. + +BUGS + This implementation of SHA-1 has not been validated by NIST and as such + is not in official compliance with the standard. + + If a message digest is to be copied to a multi-byte type (ie: an array of + five 32-bit integers) it will be necessary to perform byte swapping on + little endian machines such as the i386, alpha, and VAX. diff --git a/Vendor/sha1/sha1.c b/Vendor/sha1/sha1.c new file mode 100755 index 0000000..c2bf174 --- /dev/null +++ b/Vendor/sha1/sha1.c @@ -0,0 +1,296 @@ +/* +SHA-1 in C +By Steve Reid +100% Public Domain + +Test Vectors (from FIPS PUB 180-1) +"abc" + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 +A million repetitions of "a" + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */ +/* #define SHA1HANDSOFF * Copies data before messing with it. */ + +#define SHA1HANDSOFF + +#include +#include + +/* for uint32_t */ +#include + +#include "sha1.h" + + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +/* blk0() and blk() perform the initial expand. */ +/* I got the idea of expanding during the round function from SSLeay */ +#if BYTE_ORDER == LITTLE_ENDIAN +#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ + |(rol(block->l[i],8)&0x00FF00FF)) +#elif BYTE_ORDER == BIG_ENDIAN +#define blk0(i) block->l[i] +#else +#error "Endianness not defined!" +#endif +#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ + ^block->l[(i+2)&15]^block->l[i&15],1)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); +#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); +#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); + + +/* Hash a single 512-bit block. This is the core of the algorithm. */ + +void SHA1Transform( + uint32_t state[5], + const unsigned char buffer[64] +) +{ + uint32_t a, b, c, d, e; + + typedef union + { + unsigned char c[64]; + uint32_t l[16]; + } CHAR64LONG16; + +#ifdef SHA1HANDSOFF + CHAR64LONG16 block[1]; /* use array to appear as a pointer */ + + memcpy(block, buffer, 64); +#else + /* The following had better never be used because it causes the + * pointer-to-const buffer to be cast into a pointer to non-const. + * And the result is written through. I threw a "const" in, hoping + * this will cause a diagnostic. + */ + CHAR64LONG16 *block = (const CHAR64LONG16 *) buffer; +#endif + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a, b, c, d, e, 0); + R0(e, a, b, c, d, 1); + R0(d, e, a, b, c, 2); + R0(c, d, e, a, b, 3); + R0(b, c, d, e, a, 4); + R0(a, b, c, d, e, 5); + R0(e, a, b, c, d, 6); + R0(d, e, a, b, c, 7); + R0(c, d, e, a, b, 8); + R0(b, c, d, e, a, 9); + R0(a, b, c, d, e, 10); + R0(e, a, b, c, d, 11); + R0(d, e, a, b, c, 12); + R0(c, d, e, a, b, 13); + R0(b, c, d, e, a, 14); + R0(a, b, c, d, e, 15); + R1(e, a, b, c, d, 16); + R1(d, e, a, b, c, 17); + R1(c, d, e, a, b, 18); + R1(b, c, d, e, a, 19); + R2(a, b, c, d, e, 20); + R2(e, a, b, c, d, 21); + R2(d, e, a, b, c, 22); + R2(c, d, e, a, b, 23); + R2(b, c, d, e, a, 24); + R2(a, b, c, d, e, 25); + R2(e, a, b, c, d, 26); + R2(d, e, a, b, c, 27); + R2(c, d, e, a, b, 28); + R2(b, c, d, e, a, 29); + R2(a, b, c, d, e, 30); + R2(e, a, b, c, d, 31); + R2(d, e, a, b, c, 32); + R2(c, d, e, a, b, 33); + R2(b, c, d, e, a, 34); + R2(a, b, c, d, e, 35); + R2(e, a, b, c, d, 36); + R2(d, e, a, b, c, 37); + R2(c, d, e, a, b, 38); + R2(b, c, d, e, a, 39); + R3(a, b, c, d, e, 40); + R3(e, a, b, c, d, 41); + R3(d, e, a, b, c, 42); + R3(c, d, e, a, b, 43); + R3(b, c, d, e, a, 44); + R3(a, b, c, d, e, 45); + R3(e, a, b, c, d, 46); + R3(d, e, a, b, c, 47); + R3(c, d, e, a, b, 48); + R3(b, c, d, e, a, 49); + R3(a, b, c, d, e, 50); + R3(e, a, b, c, d, 51); + R3(d, e, a, b, c, 52); + R3(c, d, e, a, b, 53); + R3(b, c, d, e, a, 54); + R3(a, b, c, d, e, 55); + R3(e, a, b, c, d, 56); + R3(d, e, a, b, c, 57); + R3(c, d, e, a, b, 58); + R3(b, c, d, e, a, 59); + R4(a, b, c, d, e, 60); + R4(e, a, b, c, d, 61); + R4(d, e, a, b, c, 62); + R4(c, d, e, a, b, 63); + R4(b, c, d, e, a, 64); + R4(a, b, c, d, e, 65); + R4(e, a, b, c, d, 66); + R4(d, e, a, b, c, 67); + R4(c, d, e, a, b, 68); + R4(b, c, d, e, a, 69); + R4(a, b, c, d, e, 70); + R4(e, a, b, c, d, 71); + R4(d, e, a, b, c, 72); + R4(c, d, e, a, b, 73); + R4(b, c, d, e, a, 74); + R4(a, b, c, d, e, 75); + R4(e, a, b, c, d, 76); + R4(d, e, a, b, c, 77); + R4(c, d, e, a, b, 78); + R4(b, c, d, e, a, 79); + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + /* Wipe variables */ + a = b = c = d = e = 0; +#ifdef SHA1HANDSOFF + memset(block, '\0', sizeof(block)); +#endif +} + + +/* SHA1Init - Initialize new context */ + +void SHA1Init( + SHA1_CTX * context +) +{ + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + + +/* Run your data through this. */ + +void SHA1Update( + SHA1_CTX * context, + const unsigned char *data, + uint32_t len +) +{ + uint32_t i; + + uint32_t j; + + j = context->count[0]; + if ((context->count[0] += len << 3) < j) + context->count[1]++; + context->count[1] += (len >> 29); + j = (j >> 3) & 63; + if ((j + len) > 63) + { + memcpy(&context->buffer[j], data, (i = 64 - j)); + SHA1Transform(context->state, context->buffer); + for (; i + 63 < len; i += 64) + { + SHA1Transform(context->state, &data[i]); + } + j = 0; + } + else + i = 0; + memcpy(&context->buffer[j], &data[i], len - i); +} + + +/* Add padding and return the message digest. */ + +void SHA1Final( + unsigned char digest[20], + SHA1_CTX * context +) +{ + unsigned i; + + unsigned char finalcount[8]; + + unsigned char c; + +#if 0 /* untested "improvement" by DHR */ + /* Convert context->count to a sequence of bytes + * in finalcount. Second element first, but + * big-endian order within element. + * But we do it all backwards. + */ + unsigned char *fcp = &finalcount[8]; + + for (i = 0; i < 2; i++) + { + uint32_t t = context->count[i]; + + int j; + + for (j = 0; j < 4; t >>= 8, j++) + *--fcp = (unsigned char) t} +#else + for (i = 0; i < 8; i++) + { + finalcount[i] = (unsigned char) ((context->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255); /* Endian independent */ + } +#endif + c = 0200; + SHA1Update(context, &c, 1); + while ((context->count[0] & 504) != 448) + { + c = 0000; + SHA1Update(context, &c, 1); + } + SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ + for (i = 0; i < 20; i++) + { + digest[i] = (unsigned char) + ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); + } + /* Wipe variables */ + memset(context, '\0', sizeof(*context)); + memset(&finalcount, '\0', sizeof(finalcount)); +} + +void SHA1( + char *hash_out, + const char *str, + int len) +{ + SHA1_CTX ctx; + unsigned int ii; + + SHA1Init(&ctx); + for (ii=0; ii + 100% Public Domain + */ + +#include "stdint.h" + +typedef struct +{ + uint32_t state[5]; + uint32_t count[2]; + unsigned char buffer[64]; +} SHA1_CTX; + +void SHA1Transform( + uint32_t state[5], + const unsigned char buffer[64] + ); + +void SHA1Init( + SHA1_CTX * context + ); + +void SHA1Update( + SHA1_CTX * context, + const unsigned char *data, + uint32_t len + ); + +void SHA1Final( + unsigned char digest[20], + SHA1_CTX * context + ); + +void SHA1( + char *hash_out, + const char *str, + int len); + +#endif /* SHA1_H */ diff --git a/Vendor/sha1/test.c b/Vendor/sha1/test.c new file mode 100755 index 0000000..6a7eb5c --- /dev/null +++ b/Vendor/sha1/test.c @@ -0,0 +1,217 @@ +/* +SHA1 tests by Philip Woolford +100% Public Domain + */ + +#include "sha1.h" +#include "CUnit/Basic.h" +#include "stdio.h" +#include "string.h" + +#define SUCCESS 0 + +/* The suite initialization function. + * Returns zero on success, non-zero otherwise. + */ +int init_suite( + void +) +{ + return 0; +} + +/* The suite cleanup function. + * Returns zero on success, non-zero otherwise. + */ +int clean_suite( + void +) +{ + return 0; +} + +/* Test Vector 1 */ +void testvec1( + void +) +{ + char const string[] = "abc"; + char const expect[] = "a9993e364706816aba3e25717850c26c9cd0d89d"; + char result[21]; + char hexresult[41]; + size_t offset; + + /* calculate hash */ + SHA1( result, string, strlen(string) ); + + /* format the hash for comparison */ + for( offset = 0; offset < 20; offset++) { + sprintf( ( hexresult + (2*offset)), "%02x", result[offset]&0xff); + } + + CU_ASSERT( strncmp(hexresult, expect, 40) == SUCCESS ); +} + +/* Test Vector 2 */ +void testvec2( + void +) +{ + char const string[] = ""; + char const expect[] = "da39a3ee5e6b4b0d3255bfef95601890afd80709"; + char result[21]; + char hexresult[41]; + size_t offset; + + /* calculate hash */ + SHA1( result, string, strlen(string) ); + + /*format the hash for comparison */ + for( offset = 0; offset < 20; offset++) { + sprintf( ( hexresult + (2*offset)), "%02x", result[offset]&0xff); + } + + CU_ASSERT( strncmp(hexresult, expect, 40) == SUCCESS ); +} + +/* Test Vector 3 */ +void testvec3( + void +) +{ + char const string[] = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; + char const expect[] = "84983e441c3bd26ebaae4aa1f95129e5e54670f1"; + char result[21]; + char hexresult[41]; + size_t offset; + + /* calculate hash */ + SHA1( result, string, strlen(string) ); + + /* format the hash for comparison */ + for( offset = 0; offset < 20; offset++) { + sprintf( ( hexresult + (2*offset)), "%02x", result[offset]&0xff); + } + + CU_ASSERT( strncmp(hexresult, expect, 40) == SUCCESS ); +} + +/* Test Vector 4 */ +void testvec4( + void +) +{ + char const string1[] = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghij"; + char const string2[] = "klmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"; + char const expect[] = "a49b2446a02c645bf419f995b67091253a04a259"; + unsigned char result[21]; + char hexresult[41]; + size_t offset; + SHA1_CTX ctx; + + /* calculate hash */ + SHA1Init(&ctx); + SHA1Update( &ctx, (unsigned char const *)string1, strlen(string1) ); + SHA1Update( &ctx, (unsigned char const *)string2, strlen(string2) ); + SHA1Final(result, &ctx); + + /* format the hash for comparison */ + for( offset = 0; offset < 20; offset++) { + sprintf( ( hexresult + (2*offset)), "%02x", result[offset]&0xff); + } + + CU_ASSERT( strncmp(hexresult, expect, 40) == SUCCESS ); +} + +/* Test Vector 5 */ +void testvec5( + void +) +{ + char string[1000001]; + char const expect[] = "34aa973cd4c4daa4f61eeb2bdbad27316534016f"; + char result[21]; + char hexresult[41]; + int iterator; + size_t offset; + + /* generate string */ + for( iterator = 0; iterator < 1000000; iterator++) { + string[iterator] = 'a'; + } + string[1000000] = '\0'; + + /* calculate hash */ + SHA1( result, string, strlen(string) ); + + /* format the hash for comparison */ + for( offset = 0; offset < 20; offset++) { + sprintf( ( hexresult + (2*offset)), "%02x", result[offset]&0xff); + } + + CU_ASSERT( strncmp(hexresult, expect, 40) == SUCCESS ); +} + +/* Test Vector 6 */ +void testvec6( + void +) +{ + char const string[] = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno"; + char const expect[] = "7789f0c9ef7bfc40d93311143dfbe69e2017f592"; + unsigned char result[21]; + char hexresult[41]; + int iterator; + size_t offset; + SHA1_CTX ctx; + + /* calculate hash */ + SHA1Init(&ctx); + for ( iterator = 0; iterator < 16777216; iterator++) { + SHA1Update( &ctx, (unsigned char const *)string, strlen(string) ); + } + SHA1Final(result, &ctx); + + /* format the hash for comparison */ + for( offset = 0; offset < 20; offset++) { + sprintf( ( hexresult + (2*offset)), "%02x", result[offset]&0xff); + } + + CU_ASSERT( strncmp(hexresult, expect, 40) == SUCCESS ); +} + +int main( + void +) +{ + CU_pSuite pSuite = NULL; + + /* initialize the CUnit test registry */ + if (CUE_SUCCESS != CU_initialize_registry()) + return CU_get_error(); + + /* add a suite to the registry */ + pSuite = CU_add_suite("http://www.di-mgt.com.au/sha_testvectors.html", init_suite, clean_suite); + if (NULL == pSuite) { + CU_cleanup_registry(); + return CU_get_error(); + } + + /* add the tests to the suite */ + if ((NULL == CU_add_test(pSuite, "Test of Test Vector 1", testvec1)) || + (NULL == CU_add_test(pSuite, "Test of Test Vector 2", testvec2)) || + (NULL == CU_add_test(pSuite, "Test of Test Vector 3", testvec3)) || + (NULL == CU_add_test(pSuite, "Test of Test Vector 4", testvec4)) || + (NULL == CU_add_test(pSuite, "Test of Test Vector 5", testvec5)) || + (NULL == CU_add_test(pSuite, "Test of Test Vector 6", testvec6))) + { + CU_cleanup_registry(); + return CU_get_error(); + } + + /* Run all tests using the CUnit Basic interface */ + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_basic_run_tests(); + CU_cleanup_registry(); + return CU_get_error(); +}