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