I'm trying to build a set of sequences using the openssl C API. As was noted in various places, the documentation is VERY sparse on this and code samples seem to be non-existent.
I've found various suggestions on the web but none that seemed to work correctly.
I've gotten that far in order to create sequences:
#include <openssl/asn1t.h>
countdef struct StringStructure {
ASN1_INTEGER *count;
ASN1_INTEGER *asnVersion;
ASN1_OCTET_STRING *value;
} StringSequence;
DECLARE_ASN1_FUNCTIONS(StringSequence)
ASN1_SEQUENCE(StringSequence) = {
ASN1_SIMPLE(StringSequence, count, ASN1_INTEGER),
ASN1_SIMPLE(StringSequence, asnVersion, ASN1_INTEGER),
ASN1_SIMPLE(StringSequence, value, ASN1_OCTET_STRING),
} ASN1_SEQUENCE_END(StringSequence)
IMPLEMENT_ASN1_FUNCTIONS(StringSequence)
auto aSeq = StringSequence_new();
aSeq->count = ASN1_INTEGER_new();
aSeq->asnVersion = ASN1_INTEGER_new();
aSeq->value = ASN1_OCTET_STRING_new();
if (!ASN1_INTEGER_set(aSeq->count, 10) ||
!ASN1_INTEGER_set(aSeq->asnVersion, 1) ||
!ASN1_STRING_set(aSeq->value, "Test", -1)) {
// -- Error
}
auto anotherSeq = StringSequence_new();
anotherSeq->count = ASN1_INTEGER_new();
anotherSeq->asnVersion = ASN1_INTEGER_new();
anotherSeq->value = ASN1_OCTET_STRING_new();
if (!ASN1_INTEGER_set(anotherSeq->count, 32) ||
!ASN1_INTEGER_set(anotherSeq->asnVersion, 1) ||
!ASN1_STRING_set(anotherSeq->value, "Something Else", -1)) {
// -- Error
}
Where do I go from there in order to build a set of these?
The OpenSSL source code is your best documentation...
As an example of a construct like the one you are trying to build, check out the PKCS7_SIGNED ASN1 definition in crypto/pkcs7/pk7_asn1.c:
ASN1_NDEF_SEQUENCE(PKCS7_SIGNED) = {
ASN1_SIMPLE(PKCS7_SIGNED, version, ASN1_INTEGER),
ASN1_SET_OF(PKCS7_SIGNED, md_algs, X509_ALGOR),
ASN1_SIMPLE(PKCS7_SIGNED, contents, PKCS7),
ASN1_IMP_SEQUENCE_OF_OPT(PKCS7_SIGNED, cert, X509, 0),
ASN1_IMP_SET_OF_OPT(PKCS7_SIGNED, crl, X509_CRL, 1),
ASN1_SET_OF(PKCS7_SIGNED, signer_info, PKCS7_SIGNER_INFO)
} ASN1_NDEF_SEQUENCE_END(PKCS7_SIGNED)
Its second member, md_algs, is a set of X509_ALGOR, which is in itself a sequence defined in crypto/asn1/x_algor.c:
ASN1_SEQUENCE(X509_ALGOR) = {
ASN1_SIMPLE(X509_ALGOR, algorithm, ASN1_OBJECT),
ASN1_OPT(X509_ALGOR, parameter, ASN1_ANY)
} ASN1_SEQUENCE_END(X509_ALGOR)
So that field md_algs is a set of sequences, like you are asking for. The equivalent C- structure definitions can be found in include/openssl/pkcs7.h:
typedef struct pkcs7_signed_st {
ASN1_INTEGER *version; /* version 1 */
STACK_OF(X509_ALGOR) *md_algs; /* md used */
STACK_OF(X509) *cert; /* [ 0 ] */
STACK_OF(X509_CRL) *crl; /* [ 1 ] */
STACK_OF(PKCS7_SIGNER_INFO) *signer_info;
struct pkcs7_st *contents;
} PKCS7_SIGNED;
The md_algs field shows that to capture the set-construct, you need to use the STACK API, which is intended to handle collections. In your case, that would be a STACK_OF(StringSequence).
Related
I am not C programmer but have recently taking interest in it. I am trying to modify a node of a YAML file using the C libyaml library. When I try to modify the node from an event scalar data the compiler doesn't complain but I get segmentation fault errors.
while (!done)
{
/* Get the next token. */
if (!yaml_parser_parse(&parser, &event))
goto parser_error;
//yaml_parser_scan(&parser, &token);
/* Check if this is the stream end. */
if(beginServerNodes && event.type == 8) {
beginServerNodes = 0;
}
if (event.type == YAML_SCALAR_EVENT) {
if(beginServerNodes == 1) {
//I WANT TO MODIFY THIS VALUE
printf("%s\n", event.data.scalar.value);
}
if(strcmp("servers",event.data.scalar.value) == 0) {
beginServerNodes = 1;
}
}
if (event.type == YAML_STREAM_END_EVENT) {
done = 1;
}
/* Emit the token. */
if (!yaml_emitter_emit(&emitter, &event))
goto emitter_error;
}
So while in that loop when I attempt to modify the following value
event.data.scalar.value
It must be of type yaml_char_t
yaml_char_t *newHost = "10.132.16.48:6379:1 redis-001";
event.data.scalar.value = newHost;
event.data.scalar.length = sizeof(newHost);
The compiler doesn't complain and the code run by dies with segementation fault. If have seen the examples in the libyaml test directories but nothing is intuitive as far as simply editing a node, at least not to a C newb like myself.
Libyaml expect that the values of each scalar can be removed via free(). So you need to initialize this value with malloc()ed memory:
const char* newHost = "10.132.16.48:6379:1 redis-001";
event.data.scalar.value = (yaml_char_t*)strdup(newHost);
event.data.scalar.length = strlen(newHost);
I'd like to parse asn1 format under OS-X 10.11.
Unfortunately, Apple doesn't include openssl as part of their SDK anymore. instead, there's an internal package I was advised to use exposed in the following header :
SDKs/MacOSX10.11.sdk/System/Library/Frameworks/Security.framework/Versions/A/Headers/SecAsn1Coder.h
Unfortunately, the API I needed to parse the asn1 file and extract a given field, seems very different from the original openssl API.
In openssl, the function "asn1parse" defined in include/openssl/asn1.h, gets a DER formatted file, decoding it and return output text that represent the asn1 tree.
In Apple implementation, I've found "SecAsn1Decode" that may provide the same functionality. The documentation says that the output argument (void *dest) is a pointer to "a template-specific struct allocated by the caller", but i don't understand what struct should I expect and how much memory should I allocate ?
perhaps you can help me understand how to use it. any references are welcome.
There are now several snippets on GitHub showing how to call the SecAsn1Decode function, see here for example:
typedef struct {
size_t length;
unsigned char *data;
} ASN1_Data;
typedef struct {
ASN1_Data type; // INTEGER
ASN1_Data version; // INTEGER
ASN1_Data value; // OCTET STRING
} RVNReceiptAttribute;
typedef struct {
RVNReceiptAttribute **attrs;
} RVNReceiptPayload;
// ASN.1 receipt attribute template
static const SecAsn1Template kReceiptAttributeTemplate[] = {
{ SEC_ASN1_SEQUENCE, 0, NULL, sizeof(RVNReceiptAttribute) },
{ SEC_ASN1_INTEGER, offsetof(RVNReceiptAttribute, type), NULL, 0 },
{ SEC_ASN1_INTEGER, offsetof(RVNReceiptAttribute, version), NULL, 0 },
{ SEC_ASN1_OCTET_STRING, offsetof(RVNReceiptAttribute, value), NULL, 0 },
{ 0, 0, NULL, 0 }
};
// ASN.1 receipt template set
static const SecAsn1Template kSetOfReceiptAttributeTemplate[] = {
{ SEC_ASN1_SET_OF, 0, kReceiptAttributeTemplate, sizeof(RVNReceiptPayload) },
{ 0, 0, NULL, 0 }
};
And later:
NSData *payloadData = …
RVNReceiptPayload payload = { NULL };
status = SecAsn1Decode(asn1Decoder, payloadData.bytes, payloadData.length, kSetOfReceiptAttributeTemplate, &payload);
I have dlopen()'ed a library, and I want to invert back from the handle it passes to me to the full pathname of shared library. On Linux and friends, I know that I can use dlinfo() to get the linkmap and iterate through those structures, but I can't seem to find an analogue on OSX. The closest thing I can do is to either:
Use dyld_image_count() and dyld_get_image_name(), iterate over all the currently opened libraries and hope I can guess which one corresponds to my handle
Somehow find a symbol that lives inside of the handle I have, and pass that to dladdr().
If I have apriori knowledge as to a symbol name inside of the library I just opened, I can dlsym() that and then use dladdr(). That works fine. But in the general case where I have no idea what is inside this shared library, I would need to be able to enumerate symbols to do that, which I don't know how to do either.
So any tips on how to lookup the pathname of a library from its dlopen handle would be very much appreciated. Thanks!
Here is how you can get the absolute path of a handle returned by dlopen.
In order to get the absolute path, you need to call the dladdr function and retrieve the Dl_info.dli_fname field.
In order to call the dladdr function, you need to give it an address.
In order to get an address given a handle, you have to call the dlsym function with a symbol.
In order to get a symbol out of a loaded library, you have to parse the library to find its symbol table and iterate over the symbols. You need to find an external symbol because dlsym only searches for external symbols.
Put it all together and you get this:
#import <dlfcn.h>
#import <mach-o/dyld.h>
#import <mach-o/nlist.h>
#import <stdio.h>
#import <string.h>
#ifdef __LP64__
typedef struct mach_header_64 mach_header_t;
typedef struct segment_command_64 segment_command_t;
typedef struct nlist_64 nlist_t;
#else
typedef struct mach_header mach_header_t;
typedef struct segment_command segment_command_t;
typedef struct nlist nlist_t;
#endif
static const char * first_external_symbol_for_image(const mach_header_t *header)
{
Dl_info info;
if (dladdr(header, &info) == 0)
return NULL;
segment_command_t *seg_linkedit = NULL;
segment_command_t *seg_text = NULL;
struct symtab_command *symtab = NULL;
struct load_command *cmd = (struct load_command *)((intptr_t)header + sizeof(mach_header_t));
for (uint32_t i = 0; i < header->ncmds; i++, cmd = (struct load_command *)((intptr_t)cmd + cmd->cmdsize))
{
switch(cmd->cmd)
{
case LC_SEGMENT:
case LC_SEGMENT_64:
if (!strcmp(((segment_command_t *)cmd)->segname, SEG_TEXT))
seg_text = (segment_command_t *)cmd;
else if (!strcmp(((segment_command_t *)cmd)->segname, SEG_LINKEDIT))
seg_linkedit = (segment_command_t *)cmd;
break;
case LC_SYMTAB:
symtab = (struct symtab_command *)cmd;
break;
}
}
if ((seg_text == NULL) || (seg_linkedit == NULL) || (symtab == NULL))
return NULL;
intptr_t file_slide = ((intptr_t)seg_linkedit->vmaddr - (intptr_t)seg_text->vmaddr) - seg_linkedit->fileoff;
intptr_t strings = (intptr_t)header + (symtab->stroff + file_slide);
nlist_t *sym = (nlist_t *)((intptr_t)header + (symtab->symoff + file_slide));
for (uint32_t i = 0; i < symtab->nsyms; i++, sym++)
{
if ((sym->n_type & N_EXT) != N_EXT || !sym->n_value)
continue;
return (const char *)strings + sym->n_un.n_strx;
}
return NULL;
}
const char * pathname_for_handle(void *handle)
{
for (int32_t i = _dyld_image_count(); i >= 0 ; i--)
{
const char *first_symbol = first_external_symbol_for_image((const mach_header_t *)_dyld_get_image_header(i));
if (first_symbol && strlen(first_symbol) > 1)
{
handle = (void *)((intptr_t)handle | 1); // in order to trigger findExportedSymbol instead of findExportedSymbolInImageOrDependentImages. See `dlsym` implementation at http://opensource.apple.com/source/dyld/dyld-239.3/src/dyldAPIs.cpp
first_symbol++; // in order to remove the leading underscore
void *address = dlsym(handle, first_symbol);
Dl_info info;
if (dladdr(address, &info))
return info.dli_fname;
}
}
return NULL;
}
int main(int argc, const char * argv[])
{
void *libxml2 = dlopen("libxml2.dylib", RTLD_LAZY);
printf("libxml2 path: %s\n", pathname_for_handle(libxml2));
dlclose(libxml2);
return 0;
}
If you run this code, it will yield the expected result: libxml2 path: /usr/lib/libxml2.2.dylib
After about a year of using the solution provided by 0xced, we discovered an alternative method that is simpler and avoids one (rather rare) failure mode; specifically, because 0xced's code snippet iterates through each dylib currently loaded, finds the first exported symbol, attempts to resolve it in the dylib currently being sought, and returns positive if that symbol is found in that particular dylib, you can have false positives if the first exported symbol from an arbitrary library happens to be present inside of the dylib you're currently searching for.
My solution was to use _dyld_get_image_name(i) to get the absolute path of each image loaded, dlopen() that image, and compare the handle (after masking out any mode bits set by dlopen() due to usage of things like RTLD_FIRST) to ensure that this dylib is actually the same file as the handle passed into my function.
The complete function can be seen here, as a part of the Julia Language, with the relevant portion copied below:
// Iterate through all images currently in memory
for (int32_t i = _dyld_image_count(); i >= 0 ; i--) {
// dlopen() each image, check handle
const char *image_name = _dyld_get_image_name(i);
uv_lib_t *probe_lib = jl_load_dynamic_library(image_name, JL_RTLD_DEFAULT);
void *probe_handle = probe_lib->handle;
uv_dlclose(probe_lib);
// If the handle is the same as what was passed in (modulo mode bits), return this image name
if (((intptr_t)handle & (-4)) == ((intptr_t)probe_handle & (-4)))
return image_name;
}
Note that functions such as jl_load_dynamic_library() are wrappers around dlopen() that return libuv types, but the spirit of the code remains the same.
I would have preferred to add a comment to the answer to this question
but didn't have enough points. Consider the following code:
enum _config_error
{
E_SUCCESS = 0,
E_INVALID_INPUT = -1,
E_FILE_NOT_FOUND = -2, /* consider some way of returning the OS error too */
...
};
/* type to provide in your API */
typedef _config_error error_t;
/* use this to provide a perror style method to help consumers out */
struct _errordesc {
int code;
char *message;
} errordesc[] = {
{ E_SUCCESS, "No error" },
{ E_INVALID_INPUT, "Invalid input" },
{ E_FILE_NOT_FOUND, "File not found" },
...
};
How does one lookup the error description from errordesc? I can see two problems with the version I come up with:
/* add E_COUNT = 3 to enum _config_error */
const char *errorstring(error_t errnum)
{
unsigned int i;
for (i = 0; i < E_COUNT; ++i) {
if (errordesc[i].code == errnum) {
return errordesc[i].message;
}
}
return "Can't reach this point";
}
One does know the enum size and has to manually set E_COUNT to 3.
One cannot reach the return after the for loop, what to do there?
Is there a better solution?
You can calculate E_COUNT from sizeof(errordesc) / sizeof(struct _errordesc).
If you reach the end of the loop, simply return "Unknown error" or something similar.
Since your error codes seems to be consecutive (but negative) you could index directly into the array using -errnum.
A better option is to ensure all your error codes have successive values from 0 up (or down). Then you can use them as indices into errordesc[]. Of course, if they are negative, you would do something like errordesc[-errnum].
As for the number of entries in errordesc[], it's sizeof(errordesc)/sizeof(errordesc[0]). You can store it in a global variable.
There's also bsearch() in C...
I'm trying to do some metadata tagging to some video files using QTKit. I've got things down for tagging atom that take a string as their value, but having a hard time setting atoms that take an 8-bit integer as their argument. Here is what I got right now from Apple's Documentation and other various sources on the internet:
-(void) setMediaKind: (NSString *) value
{
QTMetaDataRef metaDataRef;
Movie theMovie;
OSStatus status;
theMovie = [movie quickTimeMovie];
status = QTCopyMovieMetaData (theMovie, &metaDataRef );
NSAssert(status == noErr,#"QTCopyMovieMetaData failed!");
if (status == noErr)
{
int intValue = NSSwapHostIntToBig([(NSNumber *)value intValue]);
UInt8 *dataValuePtr = (UInt8*)(&intValue);
ByteCount dataSize = sizeof(int);
if (dataValuePtr)
{
OSType key = 'stik';
QTMetaDataItem outItem;
status = QTMetaDataAddItem(metaDataRef,
kQTMetaDataStorageFormatiTunes,
kQTMetaDataKeyFormatiTunesShortForm,
(const UInt8 *)&key,
sizeof(key),
dataValuePtr,
dataSize,
kQTMetaDataTypeSignedIntegerBE,
&outItem);
NSAssert(status == noErr,#"QTMetaDataAddItem failed!");
char langCodeStr[] = "en";
status = QTMetaDataSetItemProperty(
metaDataRef,
outItem,
kPropertyClass_MetaDataItem,
kQTMetaDataItemPropertyID_Locale,
strlen(langCodeStr) + 1,
langCodeStr);
}
}
}
So the atom 'stik' sets the video's kind in iTunes. If I want to specify the video as a TV Show i'd need to assign it a value of 10. If I send #"10" to this method I don't get any errors but the video file isn't properly tagged either.
I'm sure part of my problem is I skipped learning C and went straight to Objective C so when I have to dive into C like this I have problems.