ae619048de93b2c2b18b684fc53329c5661c1477
[folly.git] / folly / ssl / OpenSSLCertUtils.cpp
1 /*
2  * Copyright 2017-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <folly/ssl/OpenSSLCertUtils.h>
17
18 #include <openssl/x509.h>
19 #include <openssl/x509v3.h>
20
21 #include <folly/ScopeGuard.h>
22
23 namespace folly {
24 namespace ssl {
25
26 Optional<std::string> OpenSSLCertUtils::getCommonName(X509& x509) {
27   auto subject = X509_get_subject_name(&x509);
28   if (!subject) {
29     return none;
30   }
31
32   auto cnLoc = X509_NAME_get_index_by_NID(subject, NID_commonName, -1);
33   if (cnLoc < 0) {
34     return none;
35   }
36
37   auto cnEntry = X509_NAME_get_entry(subject, cnLoc);
38   if (!cnEntry) {
39     return none;
40   }
41
42   auto cnAsn = X509_NAME_ENTRY_get_data(cnEntry);
43   if (!cnAsn) {
44     return none;
45   }
46
47   auto cnData = reinterpret_cast<const char*>(ASN1_STRING_data(cnAsn));
48   auto cnLen = ASN1_STRING_length(cnAsn);
49   if (!cnData || cnLen <= 0) {
50     return none;
51   }
52
53   return Optional<std::string>(std::string(cnData, cnLen));
54 }
55
56 std::vector<std::string> OpenSSLCertUtils::getSubjectAltNames(X509& x509) {
57   auto names = reinterpret_cast<STACK_OF(GENERAL_NAME)*>(
58       X509_get_ext_d2i(&x509, NID_subject_alt_name, nullptr, nullptr));
59   if (!names) {
60     return {};
61   }
62   SCOPE_EXIT {
63     sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);
64   };
65
66   std::vector<std::string> ret;
67   auto count = sk_GENERAL_NAME_num(names);
68   for (int i = 0; i < count; i++) {
69     auto genName = sk_GENERAL_NAME_value(names, i);
70     if (!genName || genName->type != GEN_DNS) {
71       continue;
72     }
73     auto nameData =
74         reinterpret_cast<const char*>(ASN1_STRING_data(genName->d.dNSName));
75     auto nameLen = ASN1_STRING_length(genName->d.dNSName);
76     if (!nameData || nameLen <= 0) {
77       continue;
78     }
79     ret.emplace_back(nameData, nameLen);
80   }
81   return ret;
82 }
83 }
84 }