17c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet// Copyright 2012 Google Inc. All Rights Reserved.
27c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet//
37c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet// Licensed under the Apache License, Version 2.0 (the "License");
47c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet// you may not use this file except in compliance with the License.
57c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet// You may obtain a copy of the License at
67c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet//
77c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet//     http://www.apache.org/licenses/LICENSE-2.0
87c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet//
97c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet// Unless required by applicable law or agreed to in writing, software
107c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet// distributed under the License is distributed on an "AS IS" BASIS,
117c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
127c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet// See the License for the specific language governing permissions and
137c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet// limitations under the License.
147c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
157c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet// Utilities for converting SSL certificates using OpenSSL functions.
167c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
177c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet#include "polo/util/certificateutil.h"
187c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
197c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet#include <glog/logging.h>
207c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
217c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetnamespace polo {
227c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetnamespace util {
237c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
247c9978567a202d6aa98beac5da5e1b3b34792862Jerome PoichetX509* CertificateUtil::X509FromPEM(std::string pem) {
257c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  BIO* bio = BIO_new_mem_buf(&pem[0], pem.size());
267c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  X509* x509 = PEM_read_bio_X509(bio, NULL, 0, NULL);
277c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  BIO_free(bio);
287c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
297c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  // Ensure that the certificate is not expired.
307c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  if (X509_cmp_current_time(X509_get_notBefore(x509)) > 0
317c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet      || X509_cmp_current_time(X509_get_notAfter(x509)) < 0) {
327c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    LOG(ERROR) << "Expired certificate";
337c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    X509_free(x509);
347c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    return NULL;
357c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  }
367c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
377c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  return x509;
387c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet}
397c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
407c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetstd::string CertificateUtil::X509ToPEM(X509* x509) {
417c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  BIO* bio = BIO_new(BIO_s_mem());
427c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  PEM_write_bio_X509(bio, x509);
437c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  BIO_flush(bio);
447c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
457c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  char* data = NULL;
467c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  size_t data_size = BIO_get_mem_data(bio, &data);
477c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
487c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  std::string pem(data, data_size);
497c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  BIO_free(bio);
507c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
517c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  return pem;
527c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet}
537c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
547c9978567a202d6aa98beac5da5e1b3b34792862Jerome PoichetEVP_PKEY* CertificateUtil::PKEYFromPEM(std::string pem,
557c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                                       std::string passphrase) {
567c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  BIO* bio = BIO_new_mem_buf(&pem[0], pem.size());
577c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  EVP_PKEY* pkey = PEM_read_bio_PrivateKey(bio, NULL, 0, &passphrase[0]);
587c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  BIO_free(bio);
597c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
607c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  return pkey;
617c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet}
627c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
637c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetstd::string CertificateUtil::PKEYToPEM(EVP_PKEY* pkey,
647c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                                       std::string passphrase) {
657c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  BIO* bio = BIO_new(BIO_s_mem());
667c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  PEM_write_bio_PrivateKey(bio, pkey, EVP_des_ede3_cbc(), NULL, 0, 0,
677c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet      &passphrase[0]);
687c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  BIO_flush(bio);
697c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
707c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  char* data = NULL;
717c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  int data_size = BIO_get_mem_data(bio, &data);
727c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
737c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  std::string pem(data, data_size);
747c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  BIO_free(bio);
757c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
767c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  return pem;
777c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet}
787c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
797c9978567a202d6aa98beac5da5e1b3b34792862Jerome PoichetEVP_PKEY* CertificateUtil::GeneratePrivateKey() {
807c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  EVP_PKEY* pkey = EVP_PKEY_new();
817c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  RSA* rsa = RSA_generate_key(1025, RSA_F4, NULL, NULL);
827c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  EVP_PKEY_assign_RSA(pkey, rsa);
837c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  return pkey;
847c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet}
857c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
867c9978567a202d6aa98beac5da5e1b3b34792862Jerome PoichetX509* CertificateUtil::GenerateSelfSignedCert(EVP_PKEY* pkey,
877c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                                              std::string subject_name,
887c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                                              uint32_t days) {
897c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  X509* x509 = X509_new();
907c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  X509_set_version(x509, 2);
917c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  ASN1_INTEGER_set(X509_get_serialNumber(x509), 0);
927c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  X509_gmtime_adj(X509_get_notBefore(x509), 0);
937c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  X509_gmtime_adj(X509_get_notAfter(x509), (int64_t) 60 * 60 * 24 * days);
947c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  X509_set_pubkey(x509, pkey);
957c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
967c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  X509_NAME* name = X509_get_subject_name(x509);
977c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  X509_NAME_add_entry_by_NID(name, NID_commonName, MBSTRING_ASC,
987c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet      (unsigned char*) &subject_name[0], -1, -1, 0);
997c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
1007c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  X509_set_issuer_name(x509, name);
1017c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  X509_sign(x509, pkey, EVP_sha256());
1027c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
1037c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  return x509;
1047c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet}
1057c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
1067c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet}  // namespace util
1077c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet}  // namespace polo
108