Why are applied implicit coding Tagged SEQUENCE in the DVCS (RFC-3029) implementation of BouncyCastle project? - dvcs

Sorry, my English is bad, but I try formulate a question.
BouncyCastle project contains the implementation of the protocol DVCS (RFC-3029).
The response(answer) to the DVCS request has the following structure
DVCSResponse ::= CHOICE {
dvCertInfo DVCSCertInfo ,
dvErrorNote [0] DVCSErrorNotice
}
DVCSCertInfo::= SEQUENCE {
version Integer DEFAULT 1 ,
dvReqInfo DVCSRequestInformation,
messageImprint DigestInfo,
serialNumber Integer,
responseTime DVCSTime,
dvStatus [0] PKIStatusInfo OPTIONAL,
policy [1] PolicyInformation OPTIONAL,
reqSignature [2] SignerInfos OPTIONAL,
certs [3] SEQUENCE SIZE (1..MAX) OF TargetEtcChain OPTIONAL,
extensions Extensions OPTIONAL
}
I am interested in the field dvStatus, here's the code from BouncyCastle in which the coding:
private static final int TAG_DV_STATUS = 0;
...
public DVCSCertInfo build()
{
ASN1EncodableVector v = new ASN1EncodableVector();
...
if (dvStatus != null)
{
// DERTaggedObject(bool explicitly, int tagNo, Org.BouncyCastle.Asn1.Asn1Encodable obj)
v.add(new DERTaggedObject(false, TAG_DV_STATUS, dvStatus)); //Why FALSE?
}
...
return DVCSCertInfo.getInstance(new DERSequence(v));
}
The field PkiStatusInfo in ASN1 as follows:
PkiStatusInfo ::= SEQUENCE {
status PKIStatus,
statusString PkiFreeText OPTIONAL,
failInfo PkiFailureInfo OPTIONAL
}
Dump of real dvcs responce:
SEQUENCE : dvCertInfo DVCSCertInfo
SEQUENCE : dvReqInfo DVCSRequestInformation
ENUMERATED : service ServiceType
INTEGER : nonce INTEGER
GENERALIZED TIME : requestTime DVCSTime
SEQUENCE : messageImprint DigestInfo
INTEGER : serialNumber Integer
GENERALIZED TIME : responseTime DVCSTime
CONTEXT SPECIFIC (0) : dvStatus [0] PKIStatusInfo
INTEGER : 0 status PKIStatus //Where SEQUENCE?
But I can not understand why it is encoded without Sequence.

If you look at RFC 3029 Appendix E, which contains the complete ASN.1 module, the third line includes "IMPLICIT TAGS". This indicates that BER or DER encodings of components with tags (such as [0]) should have the built-in UNIVERSAL tags replaced by the tag in the specification. This means that the context specific 0 is used instead of the UNIVERSAL 16 for the dvStatus component.
There are two excellent ASN.1 Books you can download free from http://www.oss.com/asn1/resources/books-whitepapers-pubs/asn1-books.html which will explain EXPLICIT vs. IMPLICIT tags clearly. You can also try your example in the free online ASN.1 compiler and encoder/decoder at http://asn1-playground.oss.com to see the effects of IMPLICIT vs. EXPLICIT tags on encodings.
Most new specifications created today use AUTOMATIC TAGS (implying implicit tagging). Many older specifications use IMPLICIT TAGS, while fewer, or more ancient specifications, tend to use EXPLICIT TAGS.

Words "IMPLICIT TAGS" not for imported types! X.208: "Note 5 – The value of “TagDefault” for the module definition affects only those types defined explicitly in the module. It does not affect the interpretation of imported types.". PKIStatusInfo - imported type from PKIXCMP (RFC 2510).
PKIXCMP {iso(1) identified-organization(3) dod(6) internet(1) security(5) mechanisms(5) pkix(7) id-mod(0) id-mod-cmp(9)}
DEFINITIONS EXPLICIT TAGS ::=
BEGIN
...
PKIStatusInfo ::= SEQUENCE {
status PKIStatus,
statusString PKIFreeText OPTIONAL,
failInfo PKIFailureInfo OPTIONAL}
...
END
PKIStatusInfo is defined EXPLICITLY!

Related

Passing string constant or literal to GCC built-ins in Ada

I've use a few intrinsics before with GNAT, but I get an error for __builtin_cpu_is when trying to pass in an Chars_Ptr:
error: parameter to builtin must be a string constant or literal
I also tried plugging the "amd" target parameter in directly, but that didn't work.
with Ada.Text_IO;
with Interfaces.C.Strings;
procedure Intrinsics is
procedure CPU_Init;
pragma Import (Intrinsic, CPU_Init, "__builtin_cpu_init");
function Is_CPU (CPU_Name : Interfaces.C.Strings.chars_ptr) return Interfaces.C.Int;
pragma Import (Intrinsic, Is_CPU, "__builtin_cpu_is");
Target : constant Interfaces.C.Strings.Chars_Ptr := Interfaces.C.Strings.New_String ("amd");
begin
CPU_Init;
-- ERROR from the below line, from Is_CPU
Ada.Text_IO.Put_Line (Interfaces.C.Int'Image (Is_CPU (Target)));
end Intrinsics;
References I've been looking at:
GCC Built-ins
Learn Ada, Interfacing w/ C
I think you hit a (current) limitation in importing GCC intrinsics in Ada programs (at least for version GCC/GNAT FSF 11.2). The best workaround is to wrap the builtin/intrinsic with string literal in a C function and then import that C wrapper function in the Ada program.
The error is thrown by the GCC back-end (see here). The built-in only accepts a string literal. This is not clear from the equivalent C signature of the built-in. The equivalent C signature suggests that any constant pointer-to-char is accepted:
int __builtin_cpu_is (const char *cpuname)
However, a simple test shows that this works:
#include <stdbool.h>
bool is_amd() {
return __builtin_cpu_is("amd") != 0;
}
But this doesn't:
#include <stdbool.h>
bool is_cpu(const char *cpuname) {
return __builtin_cpu_is(cpuname) != 0;
}
During compilation the abstract syntax tree is analyzed and the reference to the built-in is being matched along with the actual parameter that is passed in. This actual parameter must be a string literal (a specific tree node type). The string literal is then parsed/matched by GCC. Upon success, the call to the built-in in the syntax tree is (as a whole) replaced by a comparison (done here).
$ gcc -c is_amd.c --dump-tree-original && cat is_amd.c.005t.original
;; Function is_amd (null)
;; enabled by -tree-original
{
return __cpu_model.__cpu_vendor == 2 ? 1 : 0;
}
Now, it seems that the GNAT front-end is currently unable to generate the exact nodes (or node pattern) in the syntax tree that will match those expected by the built-in parser. This is likely because of the declared signature of the built-in and the fact that Ada makes a clear distinction between string values and string pointers.
The GNAT front-end compares the binding to __builtin_cpu_is with the signature declared internally by the GCC back-end and concludes that the cpuname argument must be a constant pointer-to-string. So, something like this:
function Is_CPU (CPU_Name : access constant String) return Integer;
pragma Import (Intrinsic, Is_CPU, "__builtin_cpu_is");
However, when using this signature, you cannot pass a string literal directly; you must use some indirection:
AMD : aliased constant String := "amd"
and then
Is_CPU (AMD'Access);
This indirection is (as far as I can see) preserved before the GNAT front-end hands over the syntax tree to the GCC back-end; GNAT will not "inline" the string literal (that is: will not remove the indirection; which I guess is actually a good thing as you do not want a constant string to be inlined into function calls in general: multiple functions might reference the string and if the string is very big, the effect of inlining might cause the program size to grow significantly).
On the other hand, if you want to pass a string literal directly in Ada, then you need a signature similar to
function Is_CPU (CPU_Name : String) return Integer;
pragma Import (Intrinsic, Is_CPU, "__builtin_cpu_is");
This signature, however, conflicts with the signature declared by the GCC back-end. Moreover, the GNAT front-end will complain that a string literal cannot be passed-by-copy (something that is likely required for the call to be accepted and recognized by the back-end).
So, I guess some additional logic for handling GCC built-ins with string arguments would have to be added to the GNAT front-end in order for this to work and allow something like this to compile:
function Is_AMD return Boolean is
function Is_CPU (CPU_Name : String) return Integer;
pragma Import (Intrinsic, Is_CPU, "__builtin_cpu_is");
begin
return Is_CPU ("amd") /= 0;
end Is_AMD;
Until then, wrapping the intrinsic with string literal in a separate C function (like the is_amd() example above) and then importing this C wrapper function in the Ada program will be the way to go.
Eric found a working solution:
with Ada.Unchecked_Conversion;
with Ada.Text_IO;
with Interfaces.C.Strings;
procedure Main is
procedure CPU_Init;
pragma Import (Intrinsic, CPU_Init, "__builtin_cpu_init");
function Is_CPU (CPU_Name : Interfaces.C.Strings.chars_ptr) return Integer;
pragma Import (Intrinsic, Is_CPU, "__builtin_cpu_is");
function To_Chars_Ptr is
new Ada.Unchecked_Conversion (String, Interfaces.C.Strings.chars_ptr);
begin
CPU_Init;
Ada.Text_IO.Put_Line (Integer'Image (Is_CPU (To_Chars_Ptr ("intel"))));
end;
How about trying Target as shown below
Target : constant Interfaces.C.Char_Ptr := Interfaces.C.To_C ("amd");

How To Copy data from String access to Ada.String

I have the following fragment of code
with GNAT.Command_Line; use GNAT.Command_Line;
with GNAT.Strings; use GNAT.Strings;
....
Define_Switch
(Config => Config, Output => File_Name'Access,
Long_Switch => "--file=", Switch => "-f=",
Help => "File with Composition");
....
Getopt
After parsing command line via Getopt I have access object that points to actual file name
I would like to copy this name to Ada.String.Fixed string that definded as
File_Name : String(1 .. 256);
I can print to console data from File_Name'Access as
Put_Line(File_Name.all);
I think I should provide something like copy operation then free access object.
How can I do it?
Thanks.
Alex
I guess File_Name in the code snippet defined as 'aliased GNAT.Strings.String_Access'. This is a "fat pointer" to the string object. "Fat" means it is not an address only, it is range of indices of the string. C-style Nil terminator is not used in Ada, and Nil is valid character.
You can copy data inside this string object into the another standard String object playing with indexes computations, but usually you must not do this: there is no Nil terminator, you will need to pass length of the actual data; destination string object may be smaller than necessary, and data will be truncated or exception raised; etc.
There are two right ways to do this. First one is to declare unconstrained string object and assign value to it.
declare
Fixed_File_Name : String := File_Name.all;
begin
Free (File_Name);
or use variable length string (bounded or unbounded):
declare
Unbounded_File_Name : Ada.Strings.Unbounded.Unbounded_String;
begin
Unbounded_File_Name :=
Ada.Strings.Unbounded.To_Unbounded_String (File_Name.all);
Free (File_Name.all);
Use of fixed string has important restriction: string object must be initialized exactly at the point of declaration of the object, and available only inside corresponding block/subprogram. Use of variable length string allows to declare string object outside of the scope of particular block/subprogram.

Subtype constraint for the OBJECT IDENTIFIER type: How to constrain an OID to some arc?

I am writing a specification in ASN.1. What is the formally correct syntax to restrict the range of values of an attribute with type OBJECT IDENTIFIER to a particular OID arc? E.g. I would like to achieve something like
foo OBJECT IDENTIFIER ( BELOW SUBTREE { 2 1 1 } )
The keyword BELOW SUBTREE has been made up by me for the sake of an example to make clear what I am looking for.
Elaborated example
Seemingly, my question above is not sufficiently clear as some answers suggest solutions that do not address the problem. I'll elaborate a little bit more on what I am doing and what I want to achieve. I am writing a X.509 certificate policy and must specify a X.509 profile in chapter 7. This means I have to substantiate some choices or degree of freedom which exist in the general syntax for the scope of my application. Especially, I cannot nor must not change any attribute types because this would make the result incompatible to a X.509 certificate, i.e. I can only specialize some types as long as the specialization remains compatible to the generalization.
Object identifiers are used all over the place in X.509.
As a tangible example, let's take the attribute policyIdentifier whose type is an alias of OBJECT IDENTIFIER within the object of type PolicyInformation within the certificate extention CertificatePolicies.
CertificatePolicies ::= SEQUENCE SIZE (1) OF PolicyInformation
PolicyInformation ::= SEQUENCE {
policyIdentifier CertPolicyId,
}
CertPolicyId ::= OBJECT IDENTIFIER
(I have already shortened down the ASN.1 syntax to the needs of my application.)
Let's assume I have defined the following constants
id-cp-my-policies OBJECT IDENTIFIER -- some OID arc in the private enterprise arc under my control
id-cp-my-policy-v10 OBJECT IDENTIFIER ::= { id-cp-my-policies 1 0 }
id-cp-my-policy-v11 OBJECT IDENTIFIER ::= { id-cp-my-policies 1 1 }
id-cp-my-policy-v12 OBJECT IDENTIFIER ::= { id-cp-my-policies 1 2 }
id-cp-my-policy-v20 OBJECT IDENTIFIER ::= { id-cp-my-policies 2 0 }
id-cp-my-policy-v30 OBJECT IDENTIFIER ::= { id-cp-my-policies 3 0 }
id-cp-my-policy-v31 OBJECT IDENTIFIER ::= { id-cp-my-policies 3 1 }
I want to express that CertPolicyId is a specialization of OBJECT IDENTIFIER which can only take values from the list above. Of course, I could explicitly enumerate all policy IDs by the "OR"-sytax, i.e. I could write
CertPolicyId ::= OBJECT IDENTIFIER ( id-cp-my-policy-v10 | id-cp-my-policy-v11 | id-cp-my-policy-v12 | id-cp-my-policy-v20 | id-cp-my-policy-v30 | id-cp-my-policy-v31 )
However, this does not seem very future-proof. Instead, I would like to write something like
CertPolicyId ::= OBJECT IDENTIFIER ( BELOW SUBTREE id-cp-my-policies )
I hope this example helps to understand what I want to do.
There is no formal way to constrain the OBJECT IDENTIFIER type to fall under a certain arc.
You can use the RELATIVE-OID type
You can either make the root oid implicit (let's say foo is a component of a SEQUENCE)
{
foo RELATIVE-OID -- relative to root { 2 1 1 }
}
or explicit
{
foo SEQUENCE {
root OBJECT IDENTIFIER DEFAULT { 2 1 1 },
object-id RELATIVE-OID -- relative to root
}
}
You can use this approach:
foo OBJECT IDENTIFIER ::= { 1 2 3 }
foo-bar OBJECT IDENTIFIER ::= { foo 4 }
thus, foo-bar will result in 1.2.3.4 OID value in dotted notation. Is this what you are looking for?

ASN.1: Can the SIZE constraint be used to constrain SEQUENCE (not SEQUENCE OF)

Is the following type definition valid ASN.1 syntax?
MyType ::= SEQUENCE SIZE(2) {
theID OBJECT IDENTIFIER,
someNumber INTEGER OPTIONAL,
someString PrintableString OPTIONAL
}
I want to formally constrain the sequence such that for each instantiation exactly one of both optional attributes must be present.
PS: As SEQUENCE and SEQUENCE OF are encoded exactly the same way, I have the slight hope that this syntax is valid.
This syntax is not valid. SEQUENCE is like a struct type with fields, where each field can be of different type. SEQUENCE OF is like an array, where all nested types are of same type. Thus, in SEQUENCE OF you can set constraint to array size. Same rules apply to SET and SET OF, just unordered.
I would solve your problem this way: create a CHOICE of all your optional fields (without OPTIONAL modifier) and add this CHOICE to your main type:
MyChoice ::= CHOICE {
someNumber INTEGER,
someString PrintableString
}
MyType ::= SEQUENCE {
theID OBJECT IDENTIFIER,
myChoice < MyChoice
}
In this case, theID field is mandatory and exactly one of MyChoice elements is required.

Passing struct/record from assembler to Ada

I'm attempting to pass a structure from (x86) assembler to Ada on the stack. I've been able to successfully use this pattern in C to accept to wrap a large number of arguments passed from assembly inside a struct and I'm wondering if this will work in a similar way in Ada.
Here is a (contrived, minimal) example:
When I do this, debugging the callee shows that the passed record contains uninitialised data. It appears that Ada is interpreting the C calling convention differently despite the export directive.
The RM contains information about passing structs from Ada to C, saying that it will automatically pass a record as a pointer type, but the inverse does not appear to be true. If you accept a single access type it will simply be filled with the first value on the stack, as one would expect from cdecl.
( Please excuse any minor errors, this isn't my actual code. )
#####################################################################
# Caller
#
# This pushes the values onto the stack and calls the Ada function
#####################################################################
.global __example_function
.type __example_function, #function
__example_function:
push $1
push $2
push $3
push $4
call accepts_struct
ret
----------------------------------------------------------------------------
-- Accepts_Struct
--
-- Purpose:
-- Attempts to accept arguments pass on the stack as a struct.
----------------------------------------------------------------------------
procedure Accepts_Struct (
Struct : Struct_Passed_On_Stack
)
with Export,
Convention => C,
External_Name => "accepts_struct";
----------------------------------------------------------------------------
-- Ideally the four variables passed on the stack would be accepted as
-- the values of this struct.
----------------------------------------------------------------------------
type Struct_Passed_On_Stack is
record
A : Unsigned_32;
B : Unsigned_32;
C : Unsigned_32;
D : Unsigned_32;
end record
with Convention => C;
On the other hand, this works just fine:
procedure Accepts_Struct (
A : Unsigned_32;
B : Unsigned_32;
C : Unsigned_32;
D : Unsigned_32
)
with Export,
Convention => C,
External_Name => "accepts_struct";
That's not a big deal in this minimal case, but if I'm passing 16 or more variables it gets a bit onerous. If you're wondering why I'm doing this, it's an exception handler where the processor automatically passes variables onto the stack to show register states.
Any help here would be greatly appreciated.
The record version does not work because a record is not stored on the stack. Instead 4 Unsigned_32 elements are stored on the stack. If you really want to work with a record instead of four separate unsigned integer values you can assign the four values to the members of your record within the call to "accepts_struct".
Ada expects the first entry in the stack to be a record, not an unsigned_32.
The Ada LRM, section 6.4.1 states:
For the evaluation of a parameter_association: The actual parameter is
first evaluated. For an access parameter, the access_definition is
elaborated, which creates the anonymous access type. For a parameter
(of any mode) that is passed by reference (see 6.2), a view conversion
of the actual parameter to the nominal subtype of the formal parameter
is evaluated, and the formal parameter denotes that conversion. For an
in or in out parameter that is passed by copy (see 6.2), the formal
parameter object is created, and the value of the actual parameter is
converted to the nominal subtype of the formal parameter and assigned
to the formal.
Furthermore, the passing mode for parameters is described in section 6.2:
6.2 Formal Parameter Modes
A parameter_specification declares a formal parameter of mode in, in
out, or out. Static Semantics
A parameter is passed either by copy or by reference. When a parameter
is passed by copy, the formal parameter denotes a separate object from
the actual parameter, and any information transfer between the two
occurs only before and after executing the subprogram. When a
parameter is passed by reference, the formal parameter denotes (a view
of) the object denoted by the actual parameter; reads and updates of
the formal parameter directly reference the actual parameter object.
A type is a by-copy type if it is an elementary type, or if it is a
descendant of a private type whose full type is a by-copy type. A
parameter of a by-copy type is passed by copy, unless the formal
parameter is explicitly aliased.
A type is a by-reference type if it is a descendant of one of the
following:
a tagged type;
a task or protected type;
an explicitly limited record type;
a composite type with a subcomponent of a by-reference type;
a private type whose full type is a by-reference type.
A parameter of a by-reference type is passed by reference, as is an
explicitly aliased parameter of any type. Each value of a by-reference
type has an associated object. For a parenthesized expression,
qualified_expression, or type_conversion, this object is the one
associated with the operand. For a conditional_expression, this object
is the one associated with the evaluated dependent_expression.
For other parameters, it is unspecified whether the parameter is
passed by copy or by reference.
It appears that your compiler is trying to pass the struct by reference rather than by copy. In C all parameters are passed by copy.
Maybe you already solved the problem, but if not, then you might also want to have at look at the interrupt function attribute provided by GCC (see here). I've translated a test of the GCC testsuite which pushes values to the stack (as described in section 6.12 of the Intel SDM) and reads them back in an ISR. The translated Ada version seems to work well. See here for the original C version. See the GCC ChangeLog for some additional info.
main.adb
with PR68037_1;
procedure Main is
begin
PR68037_1.Run;
end Main;
pr68037_1.ads
package PR68037_1 is
procedure Run;
end PR68037_1;
pr68037_1.adb
with System.Machine_Code;
with Ada.Assertions;
with Interfaces.C;
with GNAT.OS_Lib;
package body PR68037_1 is
-- Ada-like re-implementation of
-- gcc/testsuite/gcc.dg/guality/pr68037-1.c
subtype uword_t is Interfaces.C.unsigned_long; -- for x86-64
ERROR : constant uword_t := 16#1234567_0#;
IP : constant uword_t := 16#1234567_1#;
CS : constant uword_t := 16#1234567_2#;
FLAGS : constant uword_t := 16#1234567_3#;
SP : constant uword_t := 16#1234567_4#;
SS : constant uword_t := 16#1234567_5#;
type interrupt_frame is
record
ip : uword_t;
cs : uword_t;
flags : uword_t;
sp : uword_t;
ss : uword_t;
end record
with Convention => C;
procedure fn (frame : interrupt_frame; error : uword_t)
with Export, Convention => C, Link_Name => "__fn";
pragma Machine_Attribute (fn, "interrupt");
--------
-- fn --
--------
procedure fn (frame : interrupt_frame; error : uword_t) is
use Ada.Assertions;
use type uword_t;
begin
-- Using the assertion function here. In general, be careful when
-- calling subprograms from an ISR. For now it's OK as we will not
-- return from the ISR and not continue the execution of an interrupted
-- program.
Assert (frame.ip = IP , "Mismatch IP");
Assert (frame.cs = CS , "Mismatch CS");
Assert (frame.flags = FLAGS, "Mismatch FLAGS");
Assert (frame.sp = SP , "Mismatch SP");
Assert (frame.ss = SS , "Mismatch SS");
-- At the end of this function IRET will be executed. This will
-- result in a segmentation fault as the value for EIP is nonsense.
-- Hence, abort the program before IRET is executed.
GNAT.OS_Lib.OS_Exit (0);
end fn;
---------
-- Run --
---------
procedure Run is
use System.Machine_Code;
use ASCII;
begin
-- Mimic the processor behavior when an ISR is invoked. See also:
--
-- Intel (R) 64 and IA-32 Architectures / Software Developer's Manual
-- Volume 3 (3A, 3B, 3C & 3D) : System Programming Guide
-- Section 6.12: Exception and Interrupt Handling
--
-- Push the data to the stack and jump unconditionally to the
-- interrupt service routine.
Asm
(Template =>
"push %0" & LF &
"push %1" & LF &
"push %2" & LF &
"push %3" & LF &
"push %4" & LF &
"push %5" & LF &
"jmp __fn",
Inputs =>
(uword_t'Asm_Input ("l", SS),
uword_t'Asm_Input ("l", SP),
uword_t'Asm_Input ("l", FLAGS),
uword_t'Asm_Input ("l", CS),
uword_t'Asm_Input ("l", IP),
uword_t'Asm_Input ("l", ERROR)),
Volatile => True);
end Run;
end PR68037_1;
I compiled the program in GNAT CE 2019 with compiler options -g -mgeneral-regs-only (copied from the GCC test). Note that the parameter interrupt_frame will be passed by reference (see RM B.3 69/2).

Resources