Get RSA public key ASN.1 encode from a certificate in DER format
RSA public key ASN.1 encode is defined in PKCS#1 as follows:
RSAPublicKey :: = SEQUENCE {
modulus INTEGER, -- n
publicExponent INTEGER -- e
}
In a DER encoded certificate the SEQUENCE is encoded again as BIT STRING type, that is, it is put into the payload part of the BIT STRING.
If the public key ASN.1 encode is expected to be extracted from a certifcate, functions: d2i_X509() and X509_get0_pubkey_bitstr(const X509 *x) in OpenSSL can be used.
But each time d2i_X509() is invoked, about 352 bytes memory is leaked. CRYPTO_cleanup_all_ex_data() function can be used to solve this problem. As stated in FAQ of www.openssl.org, CRYPTO_cleanup_all_ex_data() function is a "brutal" (thread-unsafe) application-global cleanup function. Can we avoid doing this way?
Let's recall ASN.1 encode rule, usually an ASN.1 object comprises three parts:
1. Type;
2. Payload length;
3. Payload.
Firstly auxiliary functions are needed. Functions: GetPayloadByteLength(), MovePointerToPayloadStartAddress(), MovePointerToPayloadEndAddress() are designed. By invoking these functions we can count payload length and move a pointer to some special location of an ASN.1 object.
Next the structure of a DER encoded certificate is analyzed. Look at the figure blow:
The following conclusion can be drawn: The relative location of the public key encode in a DER encoded certificate is fixed!
From this point of view, if a pointer is moved forward by adequate steps, it will be located at the start point of RSAPublicKey SEQUENCE in a DER certificate.
At first, the pointer is pointed to the address of the first byte of the certificate.
Next, The pointer "jumps" into the SEQUENCE's payload. The payload is SEQUENCE type, too. So the pointer "jumps" into next SEQUENCE's payload. The pointer jumps over Context[0] (corresponds to version), INTEGER (corresponds to serial number), SEQUENCE (corresponds to signature algorithm), SEQUENCE (corresponds to issuer info), SEQUENCE (corresponds to validity date and time), SEQUENCE (corresponds to subject info). Now the pointer is pointed to SubjectPublicKeyInfo. The ASN.1 definition of SubjectPublicKeyInfo is as follows:
SubjectPublicKeyInfo ::= SEQUENCE {
algorithm AlgorithmIdentifier,
subjectPublicKey BIT STRING
}
The pointer jumps into SubjectPublicKeyInfo's payload. Next the pointer jumps over SEQUENCE (corresponds to AlgorithmIdentifier). Now the pointer is pointed to the address of the first byte of subjectPublicKey. subjectPublicKey is BIT STRING type. If RSAPublicKey SEQUENCE is needed, the pointer must be moved to the payload part of subjectPublicKey (exactly speaking, the second byte of subjectPublicKey's payload since the first byte is 0x0).
Based on the ideas above, functions MovePointerToPublicKeyBitStringEncodeStartAddress() and GetRsaPublicKeyEncodeFromCertificate() are designed to extract public key ASN.1 encode from a certificate in DER format.
All of functions and an example program are given here:
/**************************************************
* Author: HAN Wei
* Author's blog: http://blog.csdn.net/henter/
* Date: Sept 10th, 2013
* Description: the following programs demonstrates how to
get RSA public key ASN.1 encode from a certificate
in DER format
**************************************************/ #include <stdio.h>
#include <stdlib.h>
#include <string.h> /**************************************************
* Name: MovePointerToPayloadStartAddress()
* Function: locate a pointer at the start address of an ASN.1
object's payload part
* Parameters:
pointer_address [out]
ans1_object_encode [in]
* Return value:
succeed -- 0
fail -- -1
* Notes:
1. This function cannot be used for ASN.1 object of NULL type.
2. The number of bytes used to represent ASN.1 object's payload
length cannot be more than 4, that is, ASN.1 object's payload
byte length must be less than 4G.
**************************************************/
int MovePointerToPayloadStartAddress(unsigned char **pointer_address,
unsigned char *asn1_object_encode)
{
unsigned int byte_count_of_payload_length;
unsigned char *p; p=asn1_object_encode;
if ( *p==0x5 ) /* ASN.1 NULL type */
return (-1);
p++;
if ( *p==0x80 ) /* invalid DER encode */
return (-1);
if ( *p<0x80 ) /* short encoding for payload length part */
{
p++;
(*pointer_address)=p;
return 0;
}
else /* long encoding for payload length part */
{
byte_count_of_payload_length = (*p)&(0x7F);
if ( byte_count_of_payload_length > 4 )
return (-1);
p += byte_count_of_payload_length;
p++;
(*pointer_address)=p;
return 0;
}
} /**************************************************
* Name: GetPayloadByteLength()
* Function: get byte length of an ASN.1 object's payload part
* Parameters:
ans1_object_encode [in]
payload_byte_len_pointer [out]
* Return value:
succeed -- 0
fail -- -1
* Notes:
The number of bytes used to represent ASN.1 object's payload
length cannot be more than 4, that is, ASN.1 object's payload
byte length must be less than 4G.
**************************************************/
int GetPayloadByteLength(unsigned char *asn1_object_encode,
unsigned int *payload_byte_len_pointer)
{
unsigned int byte_count_of_payload_length, payload_byte_length;
unsigned char *p;
int i; payload_byte_length=0;
p=asn1_object_encode;
if ( *p==0x5 ) /* ASN.1 NULL type */
{
*payload_byte_len_pointer=0;
return 0;
}
p++;
if ( *p==0x80 )
return (-1);
if ( *p<0x80 ) /* short encoding for payload length part */
{
*payload_byte_len_pointer = *p;
return 0;
}
else /* long encoding for payload length part */
{
byte_count_of_payload_length = (*p)&(0x7F);
if ( byte_count_of_payload_length > 4 )
return (-1);
p++;
i=(int)(byte_count_of_payload_length);
while (i>0)
{
payload_byte_length = (payload_byte_length<<8) | (*p++);
i--;
}
*payload_byte_len_pointer = payload_byte_length;
return 0;
}
} /**************************************************
* Name: MovePointerToPayloadEndAddress()
* Function: locate a pointer at the end address of an ASN.1
object's payload part
* Parameters:
pointer_address [out]
ans1_object_encode [in]
* Return value:
succeed -- 0
fail -- -1
* Notes:
1. This function cannot be used for ASN.1 object of NULL type.
2. The number of bytes used to represent ASN.1 object payload
byte length cannot be more than 4, that is, ASN.1 object
payload byte length must be less than 4G.
**************************************************/
int MovePointerToPayloadEndAddress(unsigned char **pointer_address,
unsigned char *asn1_object_encode)
{
unsigned char *p;
unsigned int pay_load_byte_len; if ( GetPayloadByteLength(asn1_object_encode,
&pay_load_byte_len) )
return (-1);
if ( MovePointerToPayloadStartAddress(&p, asn1_object_encode) )
return (-1);
p = (p + pay_load_byte_len - 1);
*pointer_address = p;
return 0;
} /**************************************************
* Name: MovePointerToPublicKeyBitStringEncodeStartAddress()
* Function: locate a pointer at the start address of RSA public
key BIT STRING part in a certificate in DER format
* Parameters:
pointer_address [out]
certificate_pointer [in]
* Return value:
succeed -- 0
fail -- -1
**************************************************/
int MovePointerToPublicKeyBitStringEncodeStartAddress(unsigned char **pointer_address,
unsigned char *certificate_pointer)
{
unsigned char *p, *next_asn1_object_pointer;
int i; next_asn1_object_pointer = certificate_pointer; for (i=0; i<2; i++)
{
if ( MovePointerToPayloadStartAddress(&p, next_asn1_object_pointer) )
return (-1);
next_asn1_object_pointer=p;
} for (i=0; i<6; i++)
{
if ( MovePointerToPayloadEndAddress(&p, next_asn1_object_pointer) )
return (-1);
p++;
next_asn1_object_pointer=p;
} if ( MovePointerToPayloadStartAddress(&p, next_asn1_object_pointer) )
return (-1);
next_asn1_object_pointer=p;
if ( MovePointerToPayloadEndAddress(&p, next_asn1_object_pointer) )
return (-1);
p++; *pointer_address = p;
return 0;
} /**************************************************
* Name: GetRsaPublicKeyEncodeFromCertificate
* Function: get RSA public key ASN.1 encode from a certificate
in DER format
* Parameters:
certificate_pointer [in]
public_key_encode_pointer [in/out]
public_key_encode_byte_len_pointer [out]
* Return value:
succeed -- 0
fail -- -1
* Notes:
1. If the value of public_key_encode_pointer is NULL, the byte
length of public key encode is assigned to the variable
pointed by public_key_encode_byte_len_pointer.
2. If the value of public_key_encode_pointer is not NULL, RSA
public key ASN.1 encode is copyed to the buffer pointed
by public_key_encode_pointer, the byte length of public key
encode is assigned to the variable
pointed by public_key_encode_byte_len_pointer.
**************************************************/
int GetRsaPublicKeyEncodeFromCertificate(unsigned char *certificate_pointer,
unsigned char *public_key_encode_pointer,
unsigned int *public_key_encode_byte_len_pointer)
{
unsigned char *public_key_bit_string_start_pointer, *start_pointer, *end_pointer;
unsigned int public_key_encode_byte_len; if ( MovePointerToPublicKeyBitStringEncodeStartAddress(&public_key_bit_string_start_pointer,
certificate_pointer) )
return (-1); if ( MovePointerToPayloadStartAddress(&start_pointer, public_key_bit_string_start_pointer) )
return (-1);
start_pointer++; /* The vaule of the ASN.1 BIT STRING object's first byte is 0x0. The pointer
is moved forward by one byte so that it is pointed to the start addrss of
RSA public key SEQUENCE */ /* count the byte length of RSA public key SEQUENCE */
if ( MovePointerToPayloadEndAddress(&end_pointer, start_pointer) )
return (-1);
public_key_encode_byte_len = end_pointer - start_pointer + 1;
*public_key_encode_byte_len_pointer = public_key_encode_byte_len; if (!public_key_encode_pointer)
return 0;
else
{
memcpy(public_key_encode_pointer, start_pointer, public_key_encode_byte_len);
return 0;
}
} /**************************************************
Example:
The following progarm demonstrates how to get RSA public
key ASN.1 encode from a certificate file. The certificate
is in DER format.
**************************************************/
int main(void)
{
FILE *fp;
errno_t err;
int file_byte_len;
unsigned char *buffer;
unsigned int i;
unsigned char *public_key_encode_pointer;
unsigned int public_key_encode_byte_len; if ( err=fopen_s(&fp, "test_cert.cer", "rb") )
{
printf("Open certificate file failed!\n");
system("pause");
return (-1);
} // get file length
fseek(fp, 0L, SEEK_END);
file_byte_len=ftell(fp);
printf("The file length is %d bytes.\n", file_byte_len); // read file into buffer
if ( !(buffer=(unsigned char *)malloc(file_byte_len)) )
{
printf("malloc function failed!\n");
fclose(fp);
system("pause");
return (-1);
}
fseek(fp,0L,SEEK_SET);
fread(buffer, file_byte_len, 1, fp);
fclose(fp); // get public key ASN.1 encode byte length
if (GetRsaPublicKeyEncodeFromCertificate(buffer,
NULL,
&public_key_encode_byte_len) )
{
printf("get RSA public key encode byte length from certificate failed!\n");
free(buffer);
system("pause");
return (-1);
} if ( !(public_key_encode_pointer=(unsigned char *)malloc(public_key_encode_byte_len)) )
{
printf("malloc() function failed!\n");
free(buffer);
system("pause");
return (-1);
} // get public key ASN.1 encode
if (GetRsaPublicKeyEncodeFromCertificate(buffer,
public_key_encode_pointer,
&public_key_encode_byte_len) )
{
printf("get RSA public key encode from certificate failed!\n");
free(buffer);
system("pause");
return (-1);
} free(buffer); printf("publick key encode length is %d bytes.\n", public_key_encode_byte_len);
printf("public key encode:\n");
for (i=0; i<public_key_encode_byte_len; i++)
{
printf("0x%x ", public_key_encode_pointer[i]);
}
printf("\n"); free(public_key_encode_pointer); system("pause");
return 0;
}
The extracted ASN.1 encode of RSA public key cannot be used directly. It is an ASN.1 SEQUENCE. RSA modulus and public exponent can be obtained after this SEQUENCE is decoded.
Get RSA public key ASN.1 encode from a certificate in DER format的更多相关文章
- .NET导入openssl生成的公钥之BEGIN RSA PUBLIC KEY
.NET导入openssl生成的公钥之BEGIN RSA PUBLIC KEY 我得到了一个公钥,形式如下 -----BEGIN RSA PUBLIC KEY----- MIGJAoGBAMroxz3 ...
- 在iOS中使用OpenSSL的Public Key 进行加密
这几天一直潜心于iOS开发,刚好把遇到的问题都记录一下.这次遇到的问题就是如果根据得到的Public Key在iOS 客户端对用户名和密码进行加密. Public Key如下: -----BEGIN ...
- Github 访问时出现Permission denied (public key)
一. 发现问题: 使用 git clone 命令时出现Permission denied (public key) . 二. 解决问题: 1.首先尝试重新添加以前生成的key,添加多次,仍然不起作用. ...
- 【原创】浅析密码学在互联网支付中的应用|RSA,Hash,AES,DES,3DES,SHA1,SHA256,MD5,SSL,Private Key,Public Key
一)概述 什么是互联网支付? 当支付遇到互联网,一场革命自然不可避免.成为现实的是传统的现金支付已经“退居二线”,各种在线支付方式成为人们日常消费的主要支付方式.银行推出的网银以及第三方支付公司推出的 ...
- windows,linux,mac生成ssh public key 和 private key
https://help.launchpad.net/YourAccount/CreatingAnSSHKeyPair Creating the key How you create your SSH ...
- gpg --verify之"Can't check signature: No public key"
自从XcodeGhost之后下载软件之后也会先验证一下md5sum,现在发现后面还有gpg签名,于是也开始学习一下. gpg的文件在centos6.4上是默认安装的,其安装使用可以参照ruanyife ...
- 使用public key来做SSH authentication
public key authentication(公钥认证)是对通过敲用户名.密码方式登录服务器的一种替代办法.这种方法更加安全更具有适应性,但是更难以配置. 传统的密码认证方式中,你通过证明你你知 ...
- SSH公钥(public key)验证
安全的设置服务器 登陆,之前用用户名和密码登陆服务器 这样不安全 ,用SSH公钥(public key)验证 这个办法能很好的解决 登陆服务器 和安全登陆服务器 的特点: 目标: Client 免输 ...
- windows下git库的ssh连接,使用public key的方法
在windows下进行项目开发,使用git,通过ssh方式与git库连接,而ssh方式用public key实现连接. 首先需要下载mygit,安装后使用git bash.git bash(有GUI界 ...
随机推荐
- POJ Octal Fractions(JAVA水过)
题目链接:id=1131" target="_blank">CLICK HERE~ 尽管java一下模拟水过,可是我看到别人的一段奇妙代码,贴出和大家共享. imp ...
- 【Unity 3D】学习笔记四十:射线
射线 射线,类比的理解就是游戏中的子弹.是在3D世界里中一个点向一个方向发射的一条无终点的线.在发射的过程中,一旦与其它对象发生碰撞,就停止发射. 射线的原理 创建一个射线时,首先须要知道射线的起点和 ...
- Lucene核心--构建Lucene搜索(下篇,理论篇)
2.1.6 截取索引(Indextruncate) 一些应用程序的所以文档的大小先前是不知道的.作为控制RAM和磁盘存储空间的使用数量的安全机制,你可能想要限制每个字段允许输入索引的输入数量.一个大的 ...
- 1688: [Usaco2005 Open]Disease Manangement 疾病管理( 枚举 )
我一开始写了个状压dp..然后没有滚动就MLE了... 其实这道题直接暴力就行了... 2^15枚举每个状态, 然后检查每头牛是否能被选中, 这样是O( 2^15*1000 ), 也是和dp一样的时间 ...
- JavaScript下全选反选的Demo程序里实现checkmeonly函数 DOM
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 简要解析XMPP框架及iOS-Objective-C的使用
前言:这两天看了XMPP框架,查阅了一些资料,写下这篇文章记录一下学习笔记 一.简要解析XMPP核心部分 XMPP框架分为两个部分 1.核心部分 2.扩展部分 扩展部分主要讲好友列表(roster). ...
- Qt 无边框窗体改变大小 完美实现
近期,做项目用到无边框窗体,令人蛋疼的是无边框窗体大小的改变要像右边框那样,上下左右四周,而且要流畅. 网上也找了些代码,发现居然还要连接到windows事件,这显然不合常理,后来自己新建了demo, ...
- 在WINDOWS下 三步快速配置 eclipse c++ 环境
所需软件 1.Eclipse IDE for C/C++ Developers http://www.eclipse.org/downloads/packages/eclipse-ide-cc-dev ...
- HDU4544 湫湫系列故事――消灭兔子
HDU 4544 Tags: 数据结构,贪心 Analysis: 将兔子的血量从大到小排序,将箭的杀伤力从大到小排序,对于每一个兔子血量, 将比他大的杀伤力大的剑压入优先队列,优先队列自己重写,让它每 ...
- RedHat Linux 5.5安装JDK+Tomcat并部署Java项目
与大家分享下RedHat Linux 5.5安装JDK+Tomcat并部署Java项目的步骤,希望对大家有用. 1.下载并安装jdk 虚拟机中安装RedHat Linux 5.5 64位企业版, 这里 ...