• ASN.1 Encode an Object Identifier (OID) with OpenSSL


    OID(Object Identifier) denotes an object.
    Examples:
    ------------------------------------------------------------------
    OID                                      object
    ------------------------------------------------------------------
    1.3.14.3.2.26                       SHA-1
    2.16.840.1.101.3.4.2.1        SHA-256
    1.2.840.113549.1.7.2          PKCS-7 signedData
    ------------------------------------------------------------------

    In OpenSSL no functions are directly provided to compute the OID ASN.1 encode. At lease two methods can be taken into account.

    1. Create a temporary object by invoking function OBJ_create(), then encode it by invoking function i2d_ASN1_OBJECT().
    Implementation (Not recommended)

    /**************************************************
    * Author: HAN Wei
    * Author's blog: http://blog.csdn.net/henter/
    * Date: Oct 11th, 2014
    * Description: implement the OID ASN.1 encode function
    **************************************************/
    
    #include <stdio.h>
    #include <openssl/objects.h>
    #include <openssl/asn1.h>
    
    int Asn1EncodeOid(char *oid,
                      unsigned char *encode,
                      int *encode_len)
    {
      int new_nid, byte_len;
      ASN1_OBJECT *obj;
      unsigned char *tmp_pointer;
    
      new_nid = OBJ_create(oid, "oid example", "Object Identifier Example");
      obj = OBJ_nid2obj(new_nid);
    
      if (!encode)
      {
        byte_len = i2d_ASN1_OBJECT(obj, NULL);
    	if (byte_len <= 0)
    	{
    #ifdef _DEBUG
          printf("get ASN.1 encode byte length failed at %s, line %d!
    ", __FILE__, __LINE__);
    #endif
    	  OBJ_cleanup();
    	  return (-1);
    	}
    	else
    	{
    	  *encode_len = byte_len;
    	  OBJ_cleanup();
    	  return 0;
    	}
      }
      else
      {
        tmp_pointer = encode;
        byte_len = i2d_ASN1_OBJECT(obj, &tmp_pointer);
        if (byte_len <= 0)
        {
    #ifdef _DEBUG
          printf("ASN.1 encode OID failed at %s, line %d!
    ", __FILE__, __LINE__);
    #endif
          OBJ_cleanup();
          return (-1);
        }
        else
        {
          *encode_len = byte_len;
          OBJ_cleanup();
          return 0;
        }
      }
    }


    This is not a good implementation. OBJ_cleanup() will free all dynamically created object, so this function must be used carefully. Especially when multiple threads are running, the fact that one thread invokes OBJ_cleanup() may run the risk of cleaning object created by other threads. The consequence is unpredictable.

    2. Compute OID payload part ASN.1 encode by invoking function a2d_ASN1_OBJECT() firstly, compute the OID encode by invoking function i2d_ASN1_OBJECT() next.

    A complete Implementation (recommended)

    Header file:

    /**************************************************
    * File name: oid_encode.h
    * Author: HAN Wei
    * Author's blog: http://blog.csdn.net/henter/
    * Date: Oct 11th, 2014
    * Description: declare the OID ASN.1 encode function
    **************************************************/
    
    #ifndef HEADER_OID_ASN1_ENCODE_H
      #define HEADER_OID_ASN1_ENCODE_H
    
    #ifdef  __cplusplus
    extern "C" {
    #endif
    
    /**************************************************
    * Name: Asn1EncodeOid
    * Function: compute ASN.1 encode for a specific OID
    * Parameters:
        oid        [in]   OID string terminated with ''
        encode     [in]   buffer used to store OID ASN.1 encode
    	encode_len [out]  byte length of OID ASN.1 encode
    * Return value:
       succeed -- 0
       fail    -- -1
    * Notes:
    1. If the NULL pointer is assigned to parameter 'encode',
       this function does not perform ASN.1 encode. The OID ASN.1
       encode length is assigned to parameter 'encode_len' and
       the function returns.
    2. If the value assigned to parameter 'encode' is not NULL,
       the OID ASN.1 encode is written into the buffer pointed by
       parameter 'encode', and encode length is assigned to
       parameter 'encode_len'. In this case the buffer length is
       NOT checked before the encode is written into the buffer.
       MAKE SURE that the buffer length is big enough to accomodate
       the ASN.1 encode!
    **************************************************/
    int Asn1EncodeOid(char *oid, unsigned char *encode, int *encode_len);
    
    #ifdef  __cplusplus
    }
    #endif
    
    #endif /* end of HEADER_OID_ASN1_ENCODE_H */


    Function implementation file:

    /**************************************************
    * File name: oid_encode.c
    * Author: HAN Wei
    * Author's blog: http://blog.csdn.net/henter/
    * Date: Oct 11th, 2014
    * Description: implement the OID ASN.1 encode function
    **************************************************/
    
    #include <stdio.h>
    #include <openssl/objects.h>
    #include <openssl/asn1.h>
    
    int Asn1EncodeOid(char *oid,
                      unsigned char *encode,
    				  int *encode_len)
    {
      int payload_len, total_len;
      ASN1_OBJECT obj;
      unsigned char *tmp_pointer, *payload_encode;
    
    // get payload ASN.1 encode
      payload_len = a2d_ASN1_OBJECT(NULL, 0, oid, -1);
      if (payload_len <= 0)
      {
    #ifdef _DEBUG
        printf("get ASN.1 encode byte length failed at %s, line %d!
    ", __FILE__, __LINE__);
    #endif
        return (-1);
      }
      if ( !(payload_encode=(unsigned char *)malloc(payload_len)) )
      {
    #ifdef _DEBUG
        printf("invoke malloc() function failed at %s, line %d!
    ", __FILE__, __LINE__);
    #endif
        return (-1);
      }
      payload_len = a2d_ASN1_OBJECT(payload_encode, payload_len, oid, -1);
      if (payload_len <= 0)
      {
    #ifdef _DEBUG
        printf("ASN.1 encode payload failed at %s, line %d!
    ", __FILE__, __LINE__);
    #endif
        free(payload_encode);
        return (-1);
      }
    
    // get the whole OID ASN.1 encode
      obj.data = payload_encode;
      obj.length = payload_len;
      if (!encode)
      {
        total_len = i2d_ASN1_OBJECT(&obj, NULL);
        if (total_len <= 0)
        {
    #ifdef _DEBUG
          printf("get ASN.1 encode byte length failed at %s, line %d!
    ", __FILE__, __LINE__);
    #endif
          free(payload_encode);
          return (-1);
        }
        else
        {
          *encode_len = total_len;
          free(payload_encode);
          return 0;
        }
      }
      else
      {
        tmp_pointer = encode;
        total_len = i2d_ASN1_OBJECT(&obj, &tmp_pointer);
        if (total_len <= 0)
        {
    #ifdef _DEBUG
          printf("ASN.1 encode OID failed at %s, line %d!
    ", __FILE__, __LINE__);
    #endif
          free(payload_encode);
          return (-1);
        }
        else
        {
          *encode_len = total_len;
          free(payload_encode);
          return 0;
        }
      }
    }


    A demo program file:

    /**************************************************
    * File name: test.c
    * Author: HAN Wei
    * Author's blog: http://blog.csdn.net/henter/
    * Date: Oct 11th, 2014
    * Description: this program demonstrates how to invoke
        the OID ASN.1 encode function
    **************************************************/
    
    #include "oid_encode.h"
    #include <stdio.h>
    #include <stdlib.h>
    int main(void)
    {
      char oid[128]="2.16.840.1.101.3.4.2.1";  /* SHA-256 OID*/
      unsigned char *buffer;
      int buffer_len, i;
    
      if ( Asn1EncodeOid(oid, NULL, &buffer_len) )
      {
        printf("error detected!
    ");
    #if defined(_WIN32) || defined(_WIN64)
        system("pause");
    #endif
        return (-1);
      }
      printf("OID ASN.1 encode length is %d bytes.
    ", buffer_len);
    
      if ( !(buffer = (unsigned char *)malloc(buffer_len)) )
      {
        printf("invoke malloc() function failed!
    ");
    #if defined(_WIN32) || defined(_WIN64)
        system("pause");
    #endif
        return (-1);
      }
    
      if ( Asn1EncodeOid(oid, buffer, &buffer_len) )
      {
        printf("error detected!
    ");
        free(buffer);
    #if defined(_WIN32) || defined(_WIN64)
        system("pause");
    #endif
        return (-1);
      }
      printf("OID ASN.1 encode:
    ");
      for (i=0; i<buffer_len; i++)
        printf("0x%x  ", buffer[i]);
      printf("
    ");
    
      free(buffer);
    #if defined(_WIN32) || defined(_WIN64)
      system("pause");
    #endif
      return 0;  
    }
    

    ASN.1 encode of SHA-256 is obtained from the demo:  0x6 0x9 0x60 0x86 0x48 0x1 0x65 0x3 0x4 0x2 0x1
    This is a better implementation.

    版权声明:本文博客原创文章,博客,未经同意,不得转载。

  • 相关阅读:
    【转载】python基础-文件读写'r' 与 'rb' 和‘r+'与’rb+'区别
    python-IndexError: list index out of range
    NameError:name ‘xrange’ is not defined
    k8s 结合docker搭建私有仓库
    部署Kubernetes-dashboard
    通过Kubeadm搭建Kubernetes集群
    .net core +gogs + jenkins +docker自动化发布、部署
    .NET Core 使用ModelBinder去掉所有参数的空格
    mysql主从同步
    IdentityServer4同时使用多个GrantType进行授权和IdentityModel.Client部分源码解析
  • 原文地址:https://www.cnblogs.com/blfshiye/p/4713041.html
Copyright © 2020-2023  润新知