• 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!
    ");
        system("pause");
        return (-1);
      }
    
    // get file length
      fseek(fp, 0L, SEEK_END);
      file_byte_len=ftell(fp);
      printf("The file length is %d bytes.
    ", file_byte_len);
    
    // read file into buffer
      if ( !(buffer=(unsigned char *)malloc(file_byte_len)) )
      {
    	printf("malloc function failed!
    ");
    	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!
    ");
        free(buffer);
        system("pause");
        return (-1);
      }
    
      if ( !(public_key_encode_pointer=(unsigned char *)malloc(public_key_encode_byte_len)) )
      {
    	printf("malloc() function failed!
    ");
    	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!
    ");
        free(buffer);
        system("pause");
        return (-1);
      }
    
      free(buffer);
    
      printf("publick key encode length is %d bytes.
    ", public_key_encode_byte_len);
      printf("public key encode:
    ");
      for (i=0; i<public_key_encode_byte_len; i++)
      {
        printf("0x%x  ", public_key_encode_pointer[i]);
      }
      printf("
    ");
    
      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.

  • 相关阅读:
    sqlite 修改 id 自增值
    欧拉图与哈密顿图12:22
    nps 配置 vnc内网穿透
    0 范数、1 范数、2 范数有什么区别?
    相关测试
    golang学习笔记---channel(通道)
    golang学习笔记---pflag包
    Nginx+Keepalived配置Nginx自动启动和7*24不间断服务
    Keepalived+Nginx双机主备配置实践
    虚拟机中使用域名通过宿主window访问
  • 原文地址:https://www.cnblogs.com/keanuyaoo/p/3313394.html
Copyright © 2020-2023  润新知