Coverage Report

Created: 2025-04-11 06:34

/src/botan/src/lib/x509/alt_name.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
* (C) 2024 Jack Lloyd
3
*
4
* Botan is released under the Simplified BSD License (see license.txt)
5
*/
6
7
#include <botan/pkix_types.h>
8
9
#include <botan/ber_dec.h>
10
#include <botan/der_enc.h>
11
#include <botan/internal/int_utils.h>
12
#include <botan/internal/loadstor.h>
13
#include <botan/internal/parsing.h>
14
#include <botan/internal/stl_util.h>
15
16
namespace Botan {
17
18
10.0k
void AlternativeName::add_uri(std::string_view uri) {
19
10.0k
   if(!uri.empty()) {
20
8.54k
      m_uri.insert(std::string(uri));
21
8.54k
   }
22
10.0k
}
23
24
33.3k
void AlternativeName::add_email(std::string_view addr) {
25
33.3k
   if(!addr.empty()) {
26
21.8k
      m_email.insert(std::string(addr));
27
21.8k
   }
28
33.3k
}
29
30
0
void AlternativeName::add_dns(std::string_view dns) {
31
0
   if(!dns.empty()) {
32
0
      m_dns.insert(tolower_string(dns));
33
0
   }
34
0
}
35
36
6.33k
void AlternativeName::add_other_name(const OID& oid, const ASN1_String& value) {
37
6.33k
   m_othernames.insert(std::make_pair(oid, value));
38
6.33k
}
39
40
7.94k
void AlternativeName::add_dn(const X509_DN& dn) {
41
7.94k
   m_dn_names.insert(dn);
42
7.94k
}
43
44
7.23k
void AlternativeName::add_ipv4_address(uint32_t ip) {
45
7.23k
   m_ipv4_addr.insert(ip);
46
7.23k
}
47
48
0
size_t AlternativeName::count() const {
49
0
   const auto sum = checked_add(
50
0
      m_dns.size(), m_uri.size(), m_email.size(), m_ipv4_addr.size(), m_dn_names.size(), m_othernames.size());
51
52
0
   return BOTAN_ASSERT_IS_SOME(sum);
53
0
}
54
55
0
bool AlternativeName::has_items() const {
56
0
   return this->count() > 0;
57
0
}
58
59
0
void AlternativeName::encode_into(DER_Encoder& der) const {
60
0
   der.start_sequence();
61
62
   /*
63
   GeneralName ::= CHOICE {
64
        otherName                       [0]     OtherName,
65
        rfc822Name                      [1]     IA5String,
66
        dNSName                         [2]     IA5String,
67
        x400Address                     [3]     ORAddress,
68
        directoryName                   [4]     Name,
69
        ediPartyName                    [5]     EDIPartyName,
70
        uniformResourceIdentifier       [6]     IA5String,
71
        iPAddress                       [7]     OCTET STRING,
72
        registeredID                    [8]     OBJECT IDENTIFIER }
73
   */
74
75
0
   for(const auto& othername : m_othernames) {
76
0
      der.start_explicit(0)
77
0
         .encode(othername.first)
78
0
         .start_explicit(0)
79
0
         .encode(othername.second)
80
0
         .end_explicit()
81
0
         .end_explicit();
82
0
   }
83
84
0
   for(const auto& name : m_email) {
85
0
      ASN1_String str(name, ASN1_Type::Ia5String);
86
0
      der.add_object(ASN1_Type(1), ASN1_Class::ContextSpecific, str.value());
87
0
   }
88
89
0
   for(const auto& name : m_dns) {
90
0
      ASN1_String str(name, ASN1_Type::Ia5String);
91
0
      der.add_object(ASN1_Type(2), ASN1_Class::ContextSpecific, str.value());
92
0
   }
93
94
0
   for(const auto& name : m_dn_names) {
95
0
      der.add_object(ASN1_Type(4), ASN1_Class::ExplicitContextSpecific, name.DER_encode());
96
0
   }
97
98
0
   for(const auto& name : m_uri) {
99
0
      ASN1_String str(name, ASN1_Type::Ia5String);
100
0
      der.add_object(ASN1_Type(6), ASN1_Class::ContextSpecific, str.value());
101
0
   }
102
103
0
   for(uint32_t ip : m_ipv4_addr) {
104
0
      auto ip_buf = store_be(ip);
105
      // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange)
106
0
      der.add_object(ASN1_Type(7), ASN1_Class::ContextSpecific, ip_buf.data(), 4);
107
0
   }
108
109
0
   der.end_cons();
110
0
}
111
112
17.7k
void AlternativeName::decode_from(BER_Decoder& source) {
113
17.7k
   BER_Decoder names = source.start_sequence();
114
115
155k
   while(names.more_items()) {
116
137k
      BER_Object obj = names.get_next_object();
117
118
137k
      if(obj.is_a(0, ASN1_Class::ExplicitContextSpecific)) {
119
9.04k
         BER_Decoder othername(obj);
120
121
9.04k
         OID oid;
122
9.04k
         othername.decode(oid);
123
9.04k
         if(othername.more_items()) {
124
8.16k
            BER_Object othername_value_outer = othername.get_next_object();
125
8.16k
            othername.verify_end();
126
127
8.16k
            if(!othername_value_outer.is_a(0, ASN1_Class::ExplicitContextSpecific)) {
128
76
               throw Decoding_Error("Invalid tags on otherName value");
129
76
            }
130
131
8.09k
            BER_Decoder othername_value_inner(othername_value_outer);
132
133
8.09k
            BER_Object value = othername_value_inner.get_next_object();
134
8.09k
            othername_value_inner.verify_end();
135
136
8.09k
            if(ASN1_String::is_string_type(value.type()) && value.get_class() == ASN1_Class::Universal) {
137
6.50k
               add_othername(oid, ASN1::to_string(value), value.type());
138
6.50k
            }
139
8.09k
         }
140
128k
      } else if(obj.is_a(1, ASN1_Class::ContextSpecific)) {
141
33.3k
         add_email(ASN1::to_string(obj));
142
95.5k
      } else if(obj.is_a(2, ASN1_Class::ContextSpecific)) {
143
10.0k
         m_dns.insert(check_and_canonicalize_dns_name(ASN1::to_string(obj)));
144
85.4k
      } else if(obj.is_a(4, ASN1_Class::ContextSpecific | ASN1_Class::Constructed)) {
145
8.78k
         BER_Decoder dec(obj);
146
8.78k
         X509_DN dn;
147
8.78k
         dec.decode(dn);
148
8.78k
         this->add_dn(dn);
149
76.7k
      } else if(obj.is_a(6, ASN1_Class::ContextSpecific)) {
150
10.0k
         this->add_uri(ASN1::to_string(obj));
151
66.7k
      } else if(obj.is_a(7, ASN1_Class::ContextSpecific)) {
152
7.57k
         if(obj.length() == 4) {
153
7.23k
            const uint32_t ip = load_be<uint32_t>(obj.bits(), 0);
154
7.23k
            this->add_ipv4_address(ip);
155
7.23k
         } else if(obj.length() != 16) {
156
158
            throw Decoding_Error("Invalid IP constraint neither IPv4 or IPv6");
157
158
         }
158
7.57k
      }
159
137k
   }
160
17.7k
}
161
162
}  // namespace Botan