| #include <stdio.h> | 
 | #include <stdlib.h> | 
 | #include <string.h> | 
 | #include <openssl/pkcs7.h> | 
 | #include <openssl/asn1_mac.h> | 
 | #include <openssl/x509.h> | 
 |  | 
 | int add_signed_time(PKCS7_SIGNER_INFO *si) | 
 | 	{ | 
 | 	ASN1_UTCTIME *sign_time; | 
 |  | 
 | 	/* The last parameter is the amount to add/subtract from the current | 
 | 	 * time (in seconds) */ | 
 | 	sign_time=X509_gmtime_adj(NULL,0); | 
 | 	PKCS7_add_signed_attribute(si,NID_pkcs9_signingTime, | 
 | 		V_ASN1_UTCTIME,(char *)sign_time); | 
 | 	return(1); | 
 | 	} | 
 |  | 
 | ASN1_UTCTIME *get_signed_time(PKCS7_SIGNER_INFO *si) | 
 | 	{ | 
 | 	ASN1_TYPE *so; | 
 |  | 
 | 	so=PKCS7_get_signed_attribute(si,NID_pkcs9_signingTime); | 
 | 	if (so->type == V_ASN1_UTCTIME) | 
 | 	    return so->value.utctime; | 
 | 	return NULL; | 
 | 	} | 
 | 	 | 
 | static int signed_string_nid= -1; | 
 |  | 
 | void add_signed_string(PKCS7_SIGNER_INFO *si, char *str) | 
 | 	{ | 
 | 	ASN1_OCTET_STRING *os; | 
 |  | 
 | 	/* To a an object of OID 1.2.3.4.5, which is an octet string */ | 
 | 	if (signed_string_nid == -1) | 
 | 		signed_string_nid= | 
 | 			OBJ_create("1.2.3.4.5","OID_example","Our example OID"); | 
 | 	os=ASN1_OCTET_STRING_new(); | 
 | 	ASN1_OCTET_STRING_set(os,(unsigned char*)str,strlen(str)); | 
 | 	/* When we add, we do not free */ | 
 | 	PKCS7_add_signed_attribute(si,signed_string_nid, | 
 | 		V_ASN1_OCTET_STRING,(char *)os); | 
 | 	} | 
 |  | 
 | int get_signed_string(PKCS7_SIGNER_INFO *si, char *buf, int len) | 
 | 	{ | 
 | 	ASN1_TYPE *so; | 
 | 	ASN1_OCTET_STRING *os; | 
 | 	int i; | 
 |  | 
 | 	if (signed_string_nid == -1) | 
 | 		signed_string_nid= | 
 | 			OBJ_create("1.2.3.4.5","OID_example","Our example OID"); | 
 | 	/* To retrieve */ | 
 | 	so=PKCS7_get_signed_attribute(si,signed_string_nid); | 
 | 	if (so != NULL) | 
 | 		{ | 
 | 		if (so->type == V_ASN1_OCTET_STRING) | 
 | 			{ | 
 | 			os=so->value.octet_string; | 
 | 			i=os->length; | 
 | 			if ((i+1) > len) | 
 | 				i=len-1; | 
 | 			memcpy(buf,os->data,i); | 
 | 			return(i); | 
 | 			} | 
 | 		} | 
 | 	return(0); | 
 | 	} | 
 |  | 
 | static int signed_seq2string_nid= -1; | 
 | /* ########################################### */ | 
 | int add_signed_seq2string(PKCS7_SIGNER_INFO *si, char *str1, char *str2) | 
 | 	{ | 
 | 	/* To add an object of OID 1.9.999, which is a sequence containing | 
 | 	 * 2 octet strings */ | 
 | 	unsigned char *p; | 
 | 	ASN1_OCTET_STRING *os1,*os2; | 
 | 	ASN1_STRING *seq; | 
 | 	unsigned char *data; | 
 | 	int i,total; | 
 |  | 
 | 	if (signed_seq2string_nid == -1) | 
 | 		signed_seq2string_nid= | 
 | 			OBJ_create("1.9.9999","OID_example","Our example OID"); | 
 |  | 
 | 	os1=ASN1_OCTET_STRING_new(); | 
 | 	os2=ASN1_OCTET_STRING_new(); | 
 | 	ASN1_OCTET_STRING_set(os1,(unsigned char*)str1,strlen(str1)); | 
 | 	ASN1_OCTET_STRING_set(os2,(unsigned char*)str1,strlen(str1)); | 
 | 	i =i2d_ASN1_OCTET_STRING(os1,NULL); | 
 | 	i+=i2d_ASN1_OCTET_STRING(os2,NULL); | 
 | 	total=ASN1_object_size(1,i,V_ASN1_SEQUENCE); | 
 |  | 
 | 	data=malloc(total); | 
 | 	p=data; | 
 | 	ASN1_put_object(&p,1,i,V_ASN1_SEQUENCE,V_ASN1_UNIVERSAL); | 
 | 	i2d_ASN1_OCTET_STRING(os1,&p); | 
 | 	i2d_ASN1_OCTET_STRING(os2,&p); | 
 |  | 
 | 	seq=ASN1_STRING_new(); | 
 | 	ASN1_STRING_set(seq,data,total); | 
 | 	free(data); | 
 | 	ASN1_OCTET_STRING_free(os1); | 
 | 	ASN1_OCTET_STRING_free(os2); | 
 |  | 
 | 	PKCS7_add_signed_attribute(si,signed_seq2string_nid, | 
 | 		V_ASN1_SEQUENCE,(char *)seq); | 
 | 	return(1); | 
 | 	} | 
 |  | 
 | /* For this case, I will malloc the return strings */ | 
 | int get_signed_seq2string(PKCS7_SIGNER_INFO *si, char **str1, char **str2) | 
 | 	{ | 
 | 	ASN1_TYPE *so; | 
 |  | 
 | 	if (signed_seq2string_nid == -1) | 
 | 		signed_seq2string_nid= | 
 | 			OBJ_create("1.9.9999","OID_example","Our example OID"); | 
 | 	/* To retrieve */ | 
 | 	so=PKCS7_get_signed_attribute(si,signed_seq2string_nid); | 
 | 	if (so && (so->type == V_ASN1_SEQUENCE)) | 
 | 		{ | 
 | 		ASN1_const_CTX c; | 
 | 		ASN1_STRING *s; | 
 | 		long length; | 
 | 		ASN1_OCTET_STRING *os1,*os2; | 
 |  | 
 | 		s=so->value.sequence; | 
 | 		c.p=ASN1_STRING_data(s); | 
 | 		c.max=c.p+ASN1_STRING_length(s); | 
 | 		if (!asn1_GetSequence(&c,&length)) goto err; | 
 | 		/* Length is the length of the seqence */ | 
 |  | 
 | 		c.q=c.p; | 
 | 		if ((os1=d2i_ASN1_OCTET_STRING(NULL,&c.p,c.slen)) == NULL)  | 
 | 			goto err; | 
 | 		c.slen-=(c.p-c.q); | 
 |  | 
 | 		c.q=c.p; | 
 | 		if ((os2=d2i_ASN1_OCTET_STRING(NULL,&c.p,c.slen)) == NULL)  | 
 | 			goto err; | 
 | 		c.slen-=(c.p-c.q); | 
 |  | 
 | 		if (!asn1_const_Finish(&c)) goto err; | 
 | 		*str1=malloc(os1->length+1); | 
 | 		*str2=malloc(os2->length+1); | 
 | 		memcpy(*str1,os1->data,os1->length); | 
 | 		memcpy(*str2,os2->data,os2->length); | 
 | 		(*str1)[os1->length]='\0'; | 
 | 		(*str2)[os2->length]='\0'; | 
 | 		ASN1_OCTET_STRING_free(os1); | 
 | 		ASN1_OCTET_STRING_free(os2); | 
 | 		return(1); | 
 | 		} | 
 | err: | 
 | 	return(0); | 
 | 	} | 
 |  | 
 |  | 
 | /* ####################################### | 
 |  * THE OTHER WAY TO DO THINGS | 
 |  * ####################################### | 
 |  */ | 
 | X509_ATTRIBUTE *create_time(void) | 
 | 	{ | 
 | 	ASN1_UTCTIME *sign_time; | 
 | 	X509_ATTRIBUTE *ret; | 
 |  | 
 | 	/* The last parameter is the amount to add/subtract from the current | 
 | 	 * time (in seconds) */ | 
 | 	sign_time=X509_gmtime_adj(NULL,0); | 
 | 	ret=X509_ATTRIBUTE_create(NID_pkcs9_signingTime, | 
 | 		V_ASN1_UTCTIME,(char *)sign_time); | 
 | 	return(ret); | 
 | 	} | 
 |  | 
 | ASN1_UTCTIME *sk_get_time(STACK_OF(X509_ATTRIBUTE) *sk) | 
 | 	{ | 
 | 	ASN1_TYPE *so; | 
 | 	PKCS7_SIGNER_INFO si; | 
 |  | 
 | 	si.auth_attr=sk; | 
 | 	so=PKCS7_get_signed_attribute(&si,NID_pkcs9_signingTime); | 
 | 	if (so->type == V_ASN1_UTCTIME) | 
 | 	    return so->value.utctime; | 
 | 	return NULL; | 
 | 	} | 
 | 	 | 
 | X509_ATTRIBUTE *create_string(char *str) | 
 | 	{ | 
 | 	ASN1_OCTET_STRING *os; | 
 | 	X509_ATTRIBUTE *ret; | 
 |  | 
 | 	/* To a an object of OID 1.2.3.4.5, which is an octet string */ | 
 | 	if (signed_string_nid == -1) | 
 | 		signed_string_nid= | 
 | 			OBJ_create("1.2.3.4.5","OID_example","Our example OID"); | 
 | 	os=ASN1_OCTET_STRING_new(); | 
 | 	ASN1_OCTET_STRING_set(os,(unsigned char*)str,strlen(str)); | 
 | 	/* When we add, we do not free */ | 
 | 	ret=X509_ATTRIBUTE_create(signed_string_nid, | 
 | 		V_ASN1_OCTET_STRING,(char *)os); | 
 | 	return(ret); | 
 | 	} | 
 |  | 
 | int sk_get_string(STACK_OF(X509_ATTRIBUTE) *sk, char *buf, int len) | 
 | 	{ | 
 | 	ASN1_TYPE *so; | 
 | 	ASN1_OCTET_STRING *os; | 
 | 	int i; | 
 | 	PKCS7_SIGNER_INFO si; | 
 |  | 
 | 	si.auth_attr=sk; | 
 |  | 
 | 	if (signed_string_nid == -1) | 
 | 		signed_string_nid= | 
 | 			OBJ_create("1.2.3.4.5","OID_example","Our example OID"); | 
 | 	/* To retrieve */ | 
 | 	so=PKCS7_get_signed_attribute(&si,signed_string_nid); | 
 | 	if (so != NULL) | 
 | 		{ | 
 | 		if (so->type == V_ASN1_OCTET_STRING) | 
 | 			{ | 
 | 			os=so->value.octet_string; | 
 | 			i=os->length; | 
 | 			if ((i+1) > len) | 
 | 				i=len-1; | 
 | 			memcpy(buf,os->data,i); | 
 | 			return(i); | 
 | 			} | 
 | 		} | 
 | 	return(0); | 
 | 	} | 
 |  | 
 | X509_ATTRIBUTE *add_seq2string(PKCS7_SIGNER_INFO *si, char *str1, char *str2) | 
 | 	{ | 
 | 	/* To add an object of OID 1.9.999, which is a sequence containing | 
 | 	 * 2 octet strings */ | 
 | 	unsigned char *p; | 
 | 	ASN1_OCTET_STRING *os1,*os2; | 
 | 	ASN1_STRING *seq; | 
 | 	X509_ATTRIBUTE *ret; | 
 | 	unsigned char *data; | 
 | 	int i,total; | 
 |  | 
 | 	if (signed_seq2string_nid == -1) | 
 | 		signed_seq2string_nid= | 
 | 			OBJ_create("1.9.9999","OID_example","Our example OID"); | 
 |  | 
 | 	os1=ASN1_OCTET_STRING_new(); | 
 | 	os2=ASN1_OCTET_STRING_new(); | 
 | 	ASN1_OCTET_STRING_set(os1,(unsigned char*)str1,strlen(str1)); | 
 | 	ASN1_OCTET_STRING_set(os2,(unsigned char*)str1,strlen(str1)); | 
 | 	i =i2d_ASN1_OCTET_STRING(os1,NULL); | 
 | 	i+=i2d_ASN1_OCTET_STRING(os2,NULL); | 
 | 	total=ASN1_object_size(1,i,V_ASN1_SEQUENCE); | 
 |  | 
 | 	data=malloc(total); | 
 | 	p=data; | 
 | 	ASN1_put_object(&p,1,i,V_ASN1_SEQUENCE,V_ASN1_UNIVERSAL); | 
 | 	i2d_ASN1_OCTET_STRING(os1,&p); | 
 | 	i2d_ASN1_OCTET_STRING(os2,&p); | 
 |  | 
 | 	seq=ASN1_STRING_new(); | 
 | 	ASN1_STRING_set(seq,data,total); | 
 | 	free(data); | 
 | 	ASN1_OCTET_STRING_free(os1); | 
 | 	ASN1_OCTET_STRING_free(os2); | 
 |  | 
 | 	ret=X509_ATTRIBUTE_create(signed_seq2string_nid, | 
 | 		V_ASN1_SEQUENCE,(char *)seq); | 
 | 	return(ret); | 
 | 	} | 
 |  | 
 | /* For this case, I will malloc the return strings */ | 
 | int sk_get_seq2string(STACK_OF(X509_ATTRIBUTE) *sk, char **str1, char **str2) | 
 | 	{ | 
 | 	ASN1_TYPE *so; | 
 | 	PKCS7_SIGNER_INFO si; | 
 |  | 
 | 	if (signed_seq2string_nid == -1) | 
 | 		signed_seq2string_nid= | 
 | 			OBJ_create("1.9.9999","OID_example","Our example OID"); | 
 |  | 
 | 	si.auth_attr=sk; | 
 | 	/* To retrieve */ | 
 | 	so=PKCS7_get_signed_attribute(&si,signed_seq2string_nid); | 
 | 	if (so->type == V_ASN1_SEQUENCE) | 
 | 		{ | 
 | 		ASN1_const_CTX c; | 
 | 		ASN1_STRING *s; | 
 | 		long length; | 
 | 		ASN1_OCTET_STRING *os1,*os2; | 
 |  | 
 | 		s=so->value.sequence; | 
 | 		c.p=ASN1_STRING_data(s); | 
 | 		c.max=c.p+ASN1_STRING_length(s); | 
 | 		if (!asn1_GetSequence(&c,&length)) goto err; | 
 | 		/* Length is the length of the seqence */ | 
 |  | 
 | 		c.q=c.p; | 
 | 		if ((os1=d2i_ASN1_OCTET_STRING(NULL,&c.p,c.slen)) == NULL)  | 
 | 			goto err; | 
 | 		c.slen-=(c.p-c.q); | 
 |  | 
 | 		c.q=c.p; | 
 | 		if ((os2=d2i_ASN1_OCTET_STRING(NULL,&c.p,c.slen)) == NULL)  | 
 | 			goto err; | 
 | 		c.slen-=(c.p-c.q); | 
 |  | 
 | 		if (!asn1_const_Finish(&c)) goto err; | 
 | 		*str1=malloc(os1->length+1); | 
 | 		*str2=malloc(os2->length+1); | 
 | 		memcpy(*str1,os1->data,os1->length); | 
 | 		memcpy(*str2,os2->data,os2->length); | 
 | 		(*str1)[os1->length]='\0'; | 
 | 		(*str2)[os2->length]='\0'; | 
 | 		ASN1_OCTET_STRING_free(os1); | 
 | 		ASN1_OCTET_STRING_free(os2); | 
 | 		return(1); | 
 | 		} | 
 | err: | 
 | 	return(0); | 
 | 	} | 
 |  | 
 |  |