Skip to main content

wolfssl_src/
lib.rs

1//! Compile wolfSSL from source.
2//!
3//! This crate provides a [`Build`] API for compiling the wolfSSL C library
4//! from source via the [`cc`] crate.  It is used by `wolfcrypt-sys` when
5//! the `vendored` feature is enabled (similar to the `openssl-src` /
6//! `openssl-sys` pattern).
7//!
8//! # Usage
9//!
10//! ```rust,no_run
11//! let artifacts = wolfssl_src::Build::new().build();
12//! println!("lib dir: {}", artifacts.lib_dir.display());
13//! println!("include dir: {}", artifacts.include_dir.display());
14//! ```
15//!
16//! The builder discovers wolfSSL sources in order:
17//! 1. `source_dir()` programmatic override
18//! 2. `WOLFSSL_SRC` environment variable
19//! 3. Bundled submodule at `wolfssl-src/wolfssl/` (present after `git submodule update --init`)
20//! 4. `pkg-config` (looks for a `wolfssl` package whose prefix contains source files)
21
22use std::collections::HashSet;
23use std::env;
24use std::io::BufRead;
25use std::path::{Path, PathBuf};
26
27/// Result of a successful wolfSSL build.
28pub struct Artifacts {
29    /// Directory containing the compiled `libwolfssl.a`.
30    pub lib_dir: PathBuf,
31    /// wolfSSL source root — use as `-I` path for headers.
32    pub include_dir: PathBuf,
33    /// Directory containing `user_settings.h` — use as `-I` path.
34    pub settings_include_dir: PathBuf,
35    /// Parsed `#define` names from `user_settings.h`.
36    pub defines: HashSet<String>,
37}
38
39/// Builder for compiling wolfSSL from source.
40pub struct Build {
41    /// Path to the wolfSSL source tree.
42    source_dir: Option<PathBuf>,
43    /// Enable FIPS build.
44    fips: bool,
45}
46
47impl Build {
48    pub fn new() -> Self {
49        Build {
50            source_dir: None,
51            fips: false,
52        }
53    }
54
55    /// Set the path to the wolfSSL source tree.
56    /// If not set, defaults to `WOLFSSL_SRC` env var, then the bundled submodule, then `pkg-config`.
57    pub fn source_dir(&mut self, dir: PathBuf) -> &mut Self {
58        self.source_dir = Some(dir);
59        self
60    }
61
62    /// Enable FIPS 140-3 build.
63    pub fn fips(&mut self, enable: bool) -> &mut Self {
64        self.fips = enable;
65        self
66    }
67
68    /// Compile wolfSSL and return artifact paths.
69    pub fn build(&self) -> Artifacts {
70        let wolfssl_dir = self.resolve_source_dir();
71        let settings_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
72
73        // Select user_settings header based on active feature.
74        // Priority: cryptocb-pure > cryptocb-only > riscv-bare-metal > default.
75        let user_settings_name = if cfg!(feature = "cryptocb-pure") {
76            "user_settings_cryptocb_pure.h"
77        } else if cfg!(feature = "cryptocb-only") {
78            "user_settings_cryptocb_only.h"
79        } else if cfg!(feature = "riscv-bare-metal") {
80            "user_settings_riscv.h"
81        } else {
82            "user_settings.h"
83        };
84        let user_settings_path = settings_dir.join(user_settings_name);
85        let mut defines = parse_defines(&user_settings_path);
86        if self.fips {
87            let fips_path = settings_dir.join("user_settings_fips.h");
88            if !fips_path.exists() {
89                panic!(
90                    "FIPS build requested but {} does not exist. \
91                     Create it with the required FIPS #defines.",
92                    fips_path.display()
93                );
94            }
95            defines.extend(parse_defines(&fips_path));
96        }
97
98        // Collect source files
99        let wolfcrypt_src = wolfssl_dir.join("wolfcrypt").join("src");
100        let ssl_src = wolfssl_dir.join("src");
101
102        let mut wolfcrypt_sources: Vec<&str> = if cfg!(feature = "cryptocb-pure") {
103            CRYPTOCB_PURE_CORE_SOURCES.to_vec()
104        } else if cfg!(feature = "cryptocb-only") {
105            CRYPTOCB_ONLY_CORE_SOURCES.to_vec()
106        } else {
107            CORE_WOLFCRYPT_SOURCES.to_vec()
108        };
109        if self.fips {
110            wolfcrypt_sources.extend_from_slice(FIPS_WOLFCRYPT_SOURCES);
111        }
112        if cfg!(feature = "cryptocb-pure") {
113            append_cryptocb_pure_sources(&defines, &mut wolfcrypt_sources);
114        } else if cfg!(feature = "cryptocb-only") {
115            append_cryptocb_only_sources(&defines, &mut wolfcrypt_sources);
116        } else {
117            append_conditional_wolfcrypt_sources(&defines, &mut wolfcrypt_sources);
118        }
119        // cryptocb-only and cryptocb-pure: no SSL layer (no OPENSSL_EXTRA).
120        // riscv-bare-metal: also no SSL layer (bare-metal builds are cryptocb-based).
121        // Full builds: compile all ssl/ sources.
122        let ssl_srcs: &[&str] = if cfg!(any(
123            feature = "cryptocb-pure",
124            feature = "cryptocb-only",
125            feature = "riscv-bare-metal",
126        )) {
127            &[]
128        } else {
129            ssl_sources(&defines)
130        };
131
132        // Compile
133        let mut build = cc::Build::new();
134        build.include(&wolfssl_dir);
135
136        // For bare-metal features, shadow the default user_settings.h with the
137        // selected header so wolfSSL picks it up via -I ordering.
138        // Priority: cryptocb-pure > cryptocb-only > riscv-bare-metal.
139        if cfg!(any(feature = "riscv-bare-metal", feature = "cryptocb-only", feature = "cryptocb-pure")) {
140            let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
141            let src_name = if cfg!(feature = "cryptocb-pure") {
142                "user_settings_cryptocb_pure.h"
143            } else if cfg!(feature = "cryptocb-only") {
144                "user_settings_cryptocb_only.h"
145            } else {
146                "user_settings_riscv.h"
147            };
148            let src = settings_dir.join(src_name);
149            let dst = out_dir.join("user_settings.h");
150            std::fs::copy(&src, &dst)
151                .unwrap_or_else(|e| panic!("failed to copy {src_name}: {e}"));
152            // OUT_DIR comes first so its user_settings.h takes precedence.
153            build.include(&out_dir);
154
155            // Add bare-metal stub headers (stdio.h, etc.) if available.
156            if let Ok(stubs) = env::var("WOLFSSL_BARE_METAL_STUBS") {
157                build.include(stubs);
158            }
159
160            // Compile bare-metal helper functions (string stubs used by both
161            // user_settings_riscv.h and user_settings_cryptocb_only.h).
162            let helpers = settings_dir.join("riscv_bare_metal_helpers.c");
163            if helpers.exists() {
164                build.file(&helpers);
165                println!("cargo:rerun-if-changed={}", helpers.display());
166            }
167        }
168        build.include(&settings_dir);
169
170        build.define("WOLFSSL_USER_SETTINGS", None);
171        if self.fips {
172            build.define("HAVE_FIPS", None);
173        }
174
175        // Patch overlay: prefer files in `patches/` over the upstream source.
176        // This carries local fixes (e.g. sp_521_div_9 quotient-correction) without
177        // modifying the upstream wolfSSL tree.
178        let patches_dir = settings_dir.join("patches");
179        for src in &wolfcrypt_sources {
180            let patched = patches_dir.join(src);
181            let path = if patched.exists() {
182                patched
183            } else {
184                let upstream = wolfcrypt_src.join(src);
185                if !upstream.exists() {
186                    panic!("required wolfcrypt source not found: {}", upstream.display());
187                }
188                upstream
189            };
190            build.file(&path);
191            println!("cargo:rerun-if-changed={}", path.display());
192        }
193        for src in ssl_srcs {
194            let path = ssl_src.join(src);
195            if !path.exists() {
196                panic!("required wolfssl source not found: {}", path.display());
197            }
198            build.file(&path);
199            println!("cargo:rerun-if-changed={}", path.display());
200        }
201
202        build.warnings(false);
203        build.opt_level(2);
204        build.compile("wolfssl");
205
206        println!("cargo:rerun-if-changed={}", user_settings_path.display());
207        println!("cargo:rerun-if-changed={}", patches_dir.display());
208        if self.fips {
209            println!("cargo:rerun-if-changed={}", settings_dir.join("user_settings_fips.h").display());
210        }
211
212        Artifacts {
213            lib_dir: PathBuf::from(env::var("OUT_DIR").unwrap()),
214            include_dir: wolfssl_dir,
215            settings_include_dir: settings_dir,
216            defines,
217        }
218    }
219
220    fn resolve_source_dir(&self) -> PathBuf {
221        // 1. Programmatic override
222        if let Some(ref dir) = self.source_dir {
223            if !dir.exists() {
224                panic!("wolfssl source dir does not exist: {}", dir.display());
225            }
226            return dir.clone();
227        }
228
229        // 2. WOLFSSL_SRC env var
230        if let Ok(dir) = env::var("WOLFSSL_SRC") {
231            if !dir.is_empty() {
232                let path = PathBuf::from(&dir);
233                if !path.exists() {
234                    panic!("WOLFSSL_SRC={dir} does not exist");
235                }
236                return path;
237            }
238        }
239
240        // 3. Bundled submodule (wolfssl-src/wolfssl/ inside this crate)
241        let bundled = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("wolfssl");
242        if bundled.join("wolfcrypt/src").exists() {
243            return bundled;
244        }
245
246        // 4. pkg-config
247        if let Some(dir) = Self::find_via_pkg_config() {
248            return dir;
249        }
250
251        panic!(
252            "wolfSSL source not found. Either:\n  \
253             - Run: git submodule update --init\n  \
254             - Set WOLFSSL_SRC to the path of your wolfssl checkout\n  \
255             - Install wolfssl-dev so that pkg-config can find it"
256        );
257    }
258
259    /// Try to locate wolfSSL source via `pkg-config`.
260    ///
261    /// Queries `pkg-config --variable=prefix wolfssl` and checks whether the
262    /// returned prefix contains a wolfSSL source tree (i.e. `wolfcrypt/src/`
263    /// exists under it).  Falls back to the include directory if the prefix
264    /// doesn't contain source files — some installs place the full tree
265    /// under the include root.
266    fn find_via_pkg_config() -> Option<PathBuf> {
267        // Try the prefix first (works for source-tree installs like
268        // ./configure --prefix=/opt/wolfssl && make install)
269        if let Some(prefix) = pkg_config_var("prefix") {
270            let path = PathBuf::from(&prefix);
271            if path.join("wolfcrypt").join("src").exists() {
272                return Some(path);
273            }
274        }
275
276        // Fall back to includedir — strip the trailing /include (or
277        // /include/wolfssl) to get the root.
278        if let Some(incdir) = pkg_config_var("includedir") {
279            let path = PathBuf::from(&incdir);
280            // Try <includedir>/../ (e.g. /usr/local/include → /usr/local)
281            if let Some(parent) = path.parent() {
282                if parent.join("wolfcrypt").join("src").exists() {
283                    return Some(parent.to_path_buf());
284                }
285            }
286        }
287
288        None
289    }
290}
291
292/// Query a pkg-config variable for the `wolfssl` package.
293fn pkg_config_var(var: &str) -> Option<String> {
294    let output = std::process::Command::new("pkg-config")
295        .args(["--variable", var, "wolfssl"])
296        .output()
297        .ok()?;
298    if !output.status.success() {
299        return None;
300    }
301    let val = String::from_utf8(output.stdout).ok()?;
302    let val = val.trim();
303    if val.is_empty() {
304        None
305    } else {
306        Some(val.to_string())
307    }
308}
309
310impl Default for Build {
311    fn default() -> Self {
312        Self::new()
313    }
314}
315
316// ================================================================
317// Settings parser
318// ================================================================
319
320/// Parse a C header and return all `#define`d macro names.
321///
322/// Flat scan — does not evaluate `#if`/`#ifdef` guards.
323pub fn parse_defines(path: &Path) -> HashSet<String> {
324    let file = std::fs::File::open(path)
325        .unwrap_or_else(|e| panic!("cannot open {}: {e}", path.display()));
326    let reader = std::io::BufReader::new(file);
327    let mut defines = HashSet::new();
328    for line in reader.lines() {
329        let line = line.expect("read error");
330        let trimmed = line.trim();
331        let Some(rest) = trimmed.strip_prefix('#') else {
332            continue;
333        };
334        let rest = rest.trim_start();
335        let Some(rest) = rest.strip_prefix("define") else {
336            continue;
337        };
338        if !rest.starts_with(|c: char| c.is_ascii_whitespace()) {
339            continue;
340        }
341        let name = rest
342            .trim_start()
343            .split(|c: char| !c.is_ascii_alphanumeric() && c != '_')
344            .next()
345            .unwrap_or("");
346        if !name.is_empty() {
347            defines.insert(name.to_string());
348        }
349    }
350    defines
351}
352
353// ================================================================
354// Source file lists
355// ================================================================
356
357const CORE_WOLFCRYPT_SOURCES: &[&str] = &[
358    "aes.c",
359    "arc4.c",
360    "asn.c",
361    "blake2b.c",
362    "blake2s.c",
363    "camellia.c",
364    "cmac.c",
365    "coding.c",
366    "cpuid.c",
367    "cryptocb.c",
368    "dsa.c",
369    "error.c",
370    "hash.c",
371    "logging.c",
372    "md4.c",
373    "md5.c",
374    "memory.c",
375    "pkcs7.c",
376    "pkcs12.c",
377    "random.c",
378    "sha.c",
379    "sha256.c",
380    "signature.c",
381    "sp_int.c",
382    "sp_c32.c",
383    "sp_c64.c",
384    "srp.c",
385    "wc_encrypt.c",
386    "wc_port.c",
387    "wolfmath.c",
388];
389
390const FIPS_WOLFCRYPT_SOURCES: &[&str] = &[
391    "fips.c",
392    "fips_test.c",
393    "wolfcrypt_first.c",
394    "wolfcrypt_last.c",
395];
396
397/// Core source files for a `cryptocb-only` build.
398///
399/// Excludes everything that is not needed when all cryptographic operations
400/// are handled by CryptoCb callbacks:
401///
402/// - `sp_int.c`, `sp_c32.c`, `sp_c64.c` — SP big-integer math (the largest
403///   contributors to code size; only needed for software ECC/RSA/DH).
404/// - `wolfmath.c` — legacy mp_int math (same reason).
405/// - `arc4.c`, `blake2b.c`, `blake2s.c`, `camellia.c`, `cmac.c` — unused
406///   algorithms.
407/// - `dsa.c`, `md4.c`, `md5.c` — disabled by NO_DSA / NO_MD4 / NO_MD5.
408/// - `pkcs7.c`, `pkcs12.c`, `srp.c` — certificate containers not used in
409///   firmware.
410///
411/// Keeps: `cryptocb.c` (mandatory), `wc_port.c` (platform), `error.c`,
412/// `memory.c`, `logging.c`, `random.c` (DRBG structure), `hash.c` (routing),
413/// `sha.c`, `sha256.c`, `aes.c`, `asn.c`, `coding.c`, `signature.c`,
414/// `wc_encrypt.c`, `cpuid.c`.
415const CRYPTOCB_ONLY_CORE_SOURCES: &[&str] = &[
416    "aes.c",
417    "asn.c",
418    "coding.c",
419    "cpuid.c",
420    "cryptocb.c",
421    "error.c",
422    "hash.c",
423    "logging.c",
424    "memory.c",
425    "random.c",
426    "sha.c",
427    "sha256.c",
428    "signature.c",
429    "wc_encrypt.c",
430    "wc_port.c",
431];
432
433/// Core source files for a `cryptocb-pure` build.
434///
435/// Subset of [`CRYPTOCB_ONLY_CORE_SOURCES`] — removes everything not needed
436/// when wolfSSL is used purely as a CryptoCb routing layer with no higher-level
437/// API calls (no OpenSSL compat, no HKDF, no ASN.1 parser, no CPU feature
438/// detection, no high-level encrypt/signature wrappers):
439///
440/// - `asn.c` — ASN.1 parser (absent: no WOLFSSL_ASN_TEMPLATE, no key import/export)
441/// - `coding.c` — base64 encoding (absent: not needed for callback dispatch)
442/// - `cpuid.c` — CPU feature detection (absent: not needed for bare-metal CryptoCb)
443/// - `signature.c` — signature wrappers (absent: NO_SIG_WRAPPER is defined)
444/// - `wc_encrypt.c` — high-level encrypt wrappers (absent: not needed for CryptoCb)
445///
446/// The ssl.c layer is also excluded (no OPENSSL_EXTRA).
447const CRYPTOCB_PURE_CORE_SOURCES: &[&str] = &[
448    "aes.c",
449    "cryptocb.c",
450    "error.c",
451    "hash.c",
452    "logging.c",
453    "memory.c",
454    "random.c",
455    "sha.c",
456    "sha256.c",
457    "wc_port.c",
458];
459
460/// Append the minimal set of conditional wolfcrypt sources for a
461/// `cryptocb-only` build.
462///
463/// Only sources that provide type definitions or CryptoCb dispatch glue
464/// for algorithms used by wolfcrypt-dpe are included.  All heavy algorithm
465/// implementations (RSA, DH, Dilithium, ML-KEM, SHA-3, Ed25519, ChaCha, etc.)
466/// are omitted.
467fn append_cryptocb_only_sources(defines: &HashSet<String>, sources: &mut Vec<&'static str>) {
468    // HMAC: needed for the Hmac struct layout and CryptoCb HMAC dispatch glue.
469    if !defines.contains("NO_HMAC") {
470        sources.push("hmac.c");
471    }
472    // SHA-384/SHA-512: needed for the wc_Sha384/wc_Sha512 struct layouts.
473    if defines.contains("WOLFSSL_SHA512") || defines.contains("WOLFSSL_SHA384") {
474        sources.push("sha512.c");
475    }
476    // ECC: needed for the ecc_key struct layout and CryptoCb ECC dispatch glue.
477    if defines.contains("HAVE_ECC") {
478        sources.push("ecc.c");
479    }
480    // HKDF: pure HMAC-based KDF; HMAC calls go through CryptoCb.
481    if defines.contains("HAVE_HKDF") {
482        sources.push("kdf.c");
483    }
484    // EVP API: required when OPENSSL_EXTRA is set for wolfcrypt-rs Rust bindings.
485    if defines.contains("OPENSSL_EXTRA") || defines.contains("OPENSSL_ALL") {
486        sources.push("evp.c");
487    }
488}
489
490/// Append conditional wolfcrypt sources for a `cryptocb-pure` build.
491///
492/// Same algorithm-type guards as `cryptocb-only` but with OPENSSL_EXTRA and
493/// HAVE_HKDF absent, so `evp.c` and `kdf.c` are never added.
494fn append_cryptocb_pure_sources(defines: &HashSet<String>, sources: &mut Vec<&'static str>) {
495    // HMAC: needed for the Hmac struct layout and CryptoCb HMAC dispatch glue.
496    if !defines.contains("NO_HMAC") {
497        sources.push("hmac.c");
498    }
499    // SHA-384/512: needed for the wc_Sha384/wc_Sha512 struct layouts.
500    if defines.contains("WOLFSSL_SHA512") || defines.contains("WOLFSSL_SHA384") {
501        sources.push("sha512.c");
502    }
503    // ECC: needed for the ecc_key struct layout and CryptoCb ECC dispatch glue.
504    if defines.contains("HAVE_ECC") {
505        sources.push("ecc.c");
506    }
507    // No evp.c: OPENSSL_EXTRA is not defined in user_settings_cryptocb_pure.h.
508    // No kdf.c: HAVE_HKDF is not defined in user_settings_cryptocb_pure.h.
509}
510
511fn append_conditional_wolfcrypt_sources(defines: &HashSet<String>, sources: &mut Vec<&'static str>) {
512    if defines.contains("HAVE_CHACHA") {
513        sources.push("chacha.c");
514    }
515    if defines.contains("HAVE_CHACHA") && defines.contains("HAVE_POLY1305") {
516        sources.push("chacha20_poly1305.c");
517    }
518    if defines.contains("HAVE_POLY1305") {
519        sources.push("poly1305.c");
520    }
521    if defines.contains("HAVE_ECC") {
522        sources.push("ecc.c");
523    }
524    if defines.contains("HAVE_ED25519") || defines.contains("HAVE_CURVE25519") {
525        sources.push("curve25519.c");
526        sources.push("fe_operations.c");
527        sources.push("ge_operations.c");
528    }
529    if defines.contains("HAVE_ED25519") {
530        sources.push("ed25519.c");
531    }
532    if defines.contains("HAVE_ED448") || defines.contains("HAVE_CURVE448") {
533        sources.push("curve448.c");
534        sources.push("fe_448.c");
535        sources.push("ge_448.c");
536    }
537    if defines.contains("HAVE_ED448") {
538        sources.push("ed448.c");
539    }
540    if !defines.contains("NO_DH") {
541        sources.push("dh.c");
542    }
543    if !defines.contains("NO_RSA") {
544        sources.push("rsa.c");
545    }
546    if !defines.contains("NO_HMAC") {
547        sources.push("hmac.c");
548    }
549    if !defines.contains("NO_DES3") {
550        sources.push("des3.c");
551    }
552    if defines.contains("WOLFSSL_SHA3") {
553        sources.push("sha3.c");
554    }
555    if defines.contains("WOLFSSL_SHA512") || defines.contains("WOLFSSL_SHA384") {
556        sources.push("sha512.c");
557    }
558    if defines.contains("HAVE_DILITHIUM") {
559        sources.push("dilithium.c");
560    }
561    if defines.contains("WOLFSSL_HAVE_MLKEM") {
562        sources.push("wc_mlkem.c");
563        sources.push("wc_mlkem_poly.c");
564    }
565    if defines.contains("HAVE_HKDF") {
566        sources.push("kdf.c");
567    }
568    if defines.contains("HAVE_PBKDF2") {
569        sources.push("pwdbased.c");
570    }
571    if defines.contains("OPENSSL_EXTRA") || defines.contains("OPENSSL_ALL") {
572        sources.push("evp.c");
573    }
574}
575
576#[cfg(test)]
577mod tests {
578    use super::*;
579    use std::io::Write;
580
581    #[test]
582    fn parse_defines_basic() {
583        let mut f = tempfile::NamedTempFile::new().unwrap();
584        writeln!(f, "#define HAVE_ECC").unwrap();
585        writeln!(f, "#define HAVE_AES").unwrap();
586        writeln!(f, "#define WOLFSSL_SHA256").unwrap();
587        writeln!(f, "// not a define").unwrap();
588        writeln!(f, "int x = 5;").unwrap();
589        let defs = parse_defines(f.path());
590        assert!(defs.contains("HAVE_ECC"), "missing HAVE_ECC: {:?}", defs);
591        assert!(defs.contains("HAVE_AES"), "missing HAVE_AES: {:?}", defs);
592        assert!(defs.contains("WOLFSSL_SHA256"), "missing WOLFSSL_SHA256: {:?}", defs);
593        assert_eq!(defs.len(), 3, "unexpected defines: {:?}", defs);
594    }
595
596    #[test]
597    fn parse_defines_with_values() {
598        let mut f = tempfile::NamedTempFile::new().unwrap();
599        writeln!(f, "#define WOLFSSL_MAX_STRENGTH 1").unwrap();
600        writeln!(f, "#define HAVE_FIPS_VERSION 5").unwrap();
601        let defs = parse_defines(f.path());
602        assert!(defs.contains("WOLFSSL_MAX_STRENGTH"));
603        assert!(defs.contains("HAVE_FIPS_VERSION"));
604    }
605
606    #[test]
607    fn parse_defines_ignores_non_defines() {
608        let mut f = tempfile::NamedTempFile::new().unwrap();
609        writeln!(f, "#include <stdio.h>").unwrap();
610        writeln!(f, "#ifdef HAVE_ECC").unwrap();
611        writeln!(f, "#endif").unwrap();
612        writeln!(f, "void foo(void);").unwrap();
613        let defs = parse_defines(f.path());
614        assert!(defs.is_empty(), "should have no defines: {:?}", defs);
615    }
616
617    #[test]
618    fn parse_defines_empty_file() {
619        let f = tempfile::NamedTempFile::new().unwrap();
620        let defs = parse_defines(f.path());
621        assert!(defs.is_empty());
622    }
623}
624
625fn ssl_sources(defines: &HashSet<String>) -> &'static [&'static str] {
626    if defines.contains("OPENSSL_EXTRA") || defines.contains("OPENSSL_ALL") {
627        &[
628            "pk.c",
629            "pk_ec.c",
630            "pk_rsa.c",
631            "ssl.c",
632            "ssl_api_pk.c",
633            "ssl_asn1.c",
634            "ssl_bn.c",
635            "ssl_crypto.c",
636            "ssl_load.c",
637            "ssl_misc.c",
638            "ssl_sk.c",
639        ]
640    } else {
641        &[]
642    }
643}