c - SSL:ERROR:0906D06C:PEM routines:PEM_read_bio:no start line:pem_lib.c:644:Expecting: CERTIFICATE

标签 c linux ssl https openssl

我正在编写一个 https 代理。我的程序有两个错误。 15883:error:0906D06C:PEM routines:PEM_read_bio:no start line:pem_lib.c:644:Expecting: CERTIFICATE 15883:error:140AD009:SSL routines:SSL_CTX_use_certificate_file:PEM lib:ssl_rsa.c:491:

这是我的代码,我不知道哪里错了。请帮助我。

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <resolv.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <pthread.h>

#define SIZE 1024

#define PKEY "cacert.pem"
#define CERTT "privkey.pem"
pthread_mutex_t mut;
int counter = 0;
char url[400] = {0};


unsigned long GetIp(char domainname[250])
{
   struct sockaddr_in sin;
   struct hostent *phost;
   if((phost = gethostbyname(domainname)) == NULL)
   {
      perror("gethostbyname error\n");
      return 0;
   }
   sin.sin_addr = *((struct in_addr *)phost->h_addr_list[0]);
   const char *ip = inet_ntoa(sin.sin_addr);
   printf("ip is %s\n", ip);
   return sin.sin_addr.s_addr;
}

void ShowCerts(SSL * ssl)
{
    X509 *cert;
    char *line;

    cert = SSL_get_peer_certificate(ssl);
    if (cert != NULL) {
        printf("数字证书信息:\n");
        line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
        printf("证书: %s\n", line);
        free(line);
        line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
        printf("颁发者: %s\n", line);
        free(line);
        X509_free(cert);
    } else
        printf("无证书信息!\n");
}
char *SendWeb(char buf[])
{
   char *buffer1 ;
   int sockfd;
   int len;
   struct sockaddr_in web;
   SSL_CTX *ctx;
   SSL *ssl;
   if((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0)
   {
      perror("socket create failed!\n");
      exit(errno);
   }
   bzero(&web,sizeof(web));
   web.sin_family = AF_INET;
   web.sin_port = htons(443);
  // web.sin_addr.s_addr = inet_addr("110.75.146.111"); 
   web.sin_addr.s_addr = GetIp(url);
   if(connect(sockfd,(struct sockaddr *)&web,sizeof(web)) != 0 )
   {
      perror("connect error!\n");
      exit(errno);
   }

   ssl = SSL_new(ctx);
   SSL_set_fd(ssl,sockfd);
   if(SSL_connect(ssl) == -1)
   {
      ERR_print_errors_fp(stderr);
   }
   ShowCerts(ssl);
   bzero(buffer1,SIZE);
   len = SSL_write(ssl,buf,SIZE);
   if(len < 0)
   {
      printf("SendWeb error!\n");
   }
   else
   {
      printf("Send sucess is %s\n", buf);
   }
   len = SSL_read(ssl,buffer1,SIZE);
   if(len > 0)
   {
      printf("Recv Web : %s\n", buffer1);
   }
   else
   {
      printf("Recv Web Error!错误代码:%d,错误信息:%s.\n", errno,strerror(errno));
   }
   return buffer1;
}
char  RecvBro()
{  
   //char url[400] = {0};
   int i, sockfd , client_fd,new_fd;
   struct sockaddr_in mim_ser,brow;
   int len;
   char *index_start,*index_end,*buf;
   SSL_CTX *ctx;
   ctx = SSL_CTX_new(SSLv23_server_method());//以ssl v2 v3 标准敬爱内容方式产生一个SSL_CTX 
   if(ctx == NULL)
   {
      ERR_print_errors_fp(stdout);
      exit(1);
   }
//载入用户数字证书,发给客户端,包含公钥
   if(!SSL_CTX_use_certificate_file(ctx,CERTT,SSL_FILETYPE_PEM))
   {
      ERR_print_errors_fp(stdout);
      exit(1);
   }
//载入用户私钥
   if(SSL_CTX_use_PrivateKey_file(ctx,PKEY,SSL_FILETYPE_PEM))
   {
      ERR_print_errors_fp(stdout);
      exit(1);
   }
   if(!SSL_CTX_check_private_key(ctx))
   {
      ERR_print_errors_fp(stdout);
      exit(1);
   }

   if((sockfd=socket(PF_INET,SOCK_STREAM,0))== -1)
   {
      perror("socket create failed");
      exit(1);
   }
   bzero(&mim_ser,sizeof(mim_ser));
   mim_ser.sin_family = PF_INET;
   mim_ser.sin_port = htons(443);
   mim_ser.sin_addr.s_addr = INADDR_ANY;

   if((bind(sockfd,(struct sockaddr *)&mim_ser,sizeof(struct sockaddr))) == -1)
   {
      perror("bind failed");
      exit(1);
   }

   if(listen(sockfd,10) == -1)
   {
      perror("listen error");
      exit(1);
   }


      SSL *ssl;
      int len2 = sizeof (struct sockaddr);
      if((new_fd = accept(sockfd,(struct sockaddr *)&brow,&len2)) == -1)
      {
         perror("accept error");
         exit(1);
      }
      //基于ctx产生一个新的ssl
      ssl = SSL_new(ctx);
      SSL_set_fd(ssl,new_fd);//将连接用户的socket加入SSL
      if(SSL_accept(ssl) == -1)
      {
          perror("accept");
          close(new_fd);

      }
      buf = (char *)malloc(SIZE);
     // char buf[SIZE]= {0};
      bzero(buf,SIZE);
      len = SSL_read(ssl,buf,SIZE);
      if(len > 0)
      {
         printf("recv from browser is %s\n",buf);
      }
      else
      {
         printf("RECV ERROR!错误代码:%s,错误信息:%s\n",errno,strerror);

      }
      index_start = strstr(buf,"Host:");
      index_end = strstr(index_end,"\r\n");
      if(index_start == NULL ||index_end == NULL)
      {
         perror("index_start or index_end is NULL\n");
      }
      if((i = (int)(index_start - index_end )) <= 0)
      {
         perror("index_start - index_end <= 0 \n");
      }
      bzero(url,400);
      strncpy(url,index_start + 6, i-6);


      buf = SendWeb(buf);
      len = SSL_write(ssl,buf,SIZE);
      if(len <= 0)
      {
         printf("\nSend sucess!\n");
      }

}
int main ()
{  
   ERR_load_BIO_strings();
   SSL_library_init();//ssl库初始化
   OpenSSL_add_all_algorithms();//载入所有ssl算法
   SSL_load_error_strings();//载入所有ssl从错误消息
   pthread_mutex_init(&mut,NULL);

   while(1)
   {  
      pthread_t work_thread;
      if(pthread_create(&work_thread,NULL,(void *)&RecvBro,NULL))
      {
         perror("create thread error\n");
      } 
      else 
      {
         pthread_mutex_lock(&mut);
         counter++;
         pthread_mutex_unlock(&mut);
         pthread_detach(work_thread);
      }
   } 
   pthread_mutex_destroy(&mut);   
}

最佳答案

首先,您似乎有错字和这两行:

#define PKEY "cacert.pem"
#define CERTT "privkey.pem"

可能应该改为

#define CERTT "cacert.pem"
#define PKEY "privkey.pem"

即使这样还不够。检查下面列出的项目

1) SSL_CTX_use_certificate_file() 用于加载与私钥相对应的证书,而不是 CA 证书(如文件名“cacert.pem”所示)。您可能会发现以下答案有助于快速理解所有这些:Starting to use OpenSSL

您应该使用 SSL_CTX_load_verify_locations() 来指定带有 CA 证书的文件,如下所示:

SSL_CTX_load_verify_locations(ctx, "cacert.pem", NULL);

参见 the documentation对于此 API。

2) PEM 类型的证书文件(SSL_CTX_use_certificate_file() with SSL_FILETYPE_PEM 和 SSL_CTX_load_verify_locations())应该有破折号页眉和页脚,如下所示:

-----BEGIN CERTIFICATE-----
... (certificate in base64 encoding) ...
-----END CERTIFICATE-----

错误 9478:error:0906D06C:PEM routines:PEM_read_bio:no start line:pem_lib.c:644:Expecting: CERTIFICATE 表明您没有那些破折号页眉/页脚行你的文件。

关于c - SSL:ERROR:0906D06C:PEM routines:PEM_read_bio:no start line:pem_lib.c:644:Expecting: CERTIFICATE,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21108971/

相关文章:

ruby-on-rails - Rails SSL 证书问题 + 来自 RVM 的神秘 "curl: Remote file name has no length!"

c++ - 如何将数据传递给正在运行的线程

c++ - 从二维数组到一维数组的转换

c - 使用 C 创建子进程和父进程

python - CentOS安装后看不到python3.8

c# - 强制 SSL session 在服务器或客户端超时

C动态分配结构,使用scanf时出现段错误

c - C 中结构体定义的变体

linux - Visual Studio 2017 crlf/lf

android - 如何在 Glide 中结合自签名 SSL 证书和 alltrusted context