Fix build and code structure improvements. New but essential UI functionality. CI improvements. Documentation improvements. AI module improvements.

This commit is contained in:
StellaOps Bot
2025-12-26 21:54:17 +02:00
parent 335ff7da16
commit c2b9cd8d1f
3717 changed files with 264714 additions and 48202 deletions

View File

@@ -0,0 +1,508 @@
using System.Collections.Immutable;
using System.Text.Json;
using System.Text.Json.Nodes;
using StellaOps.Scanner.Emit.Cbom;
namespace StellaOps.Scanner.Emit.Composition;
/// <summary>
/// Enhances CycloneDX 1.7 JSON with CBOM (Cryptographic BOM) properties.
/// This is a post-processor that injects cryptographicProperties into components
/// since CycloneDX.Core doesn't natively support 1.7 CBOM yet.
/// </summary>
public static class CycloneDxCbomWriter
{
/// <summary>
/// Enhances a CycloneDX JSON with CBOM data.
/// </summary>
/// <param name="cycloneDxJson">The CycloneDX JSON (should be 1.7 format).</param>
/// <param name="cryptoAssetsByComponent">Crypto assets indexed by component bom-ref.</param>
/// <returns>Enhanced JSON with cryptographicProperties.</returns>
public static string InjectCbom(
string cycloneDxJson,
ImmutableDictionary<string, ImmutableArray<CryptoAsset>> cryptoAssetsByComponent)
{
if (string.IsNullOrEmpty(cycloneDxJson) || cryptoAssetsByComponent.IsEmpty)
{
return cycloneDxJson;
}
var root = JsonNode.Parse(cycloneDxJson);
if (root is not JsonObject bomObj)
{
return cycloneDxJson;
}
// Ensure specVersion is 1.7
if (bomObj["specVersion"]?.GetValue<string>() is not "1.7")
{
bomObj["specVersion"] = "1.7";
}
// Process components array
if (bomObj["components"] is JsonArray componentsArray)
{
foreach (var componentNode in componentsArray)
{
if (componentNode is not JsonObject componentObj)
continue;
var bomRef = componentObj["bom-ref"]?.GetValue<string>();
if (string.IsNullOrEmpty(bomRef))
continue;
if (cryptoAssetsByComponent.TryGetValue(bomRef, out var assets) && !assets.IsEmpty)
{
var cryptoProps = BuildCryptoProperties(assets);
if (cryptoProps != null)
{
componentObj["cryptographicProperties"] = cryptoProps;
}
}
}
}
return bomObj.ToJsonString(new JsonSerializerOptions
{
WriteIndented = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull
});
}
/// <summary>
/// Enhances CycloneDX artifact bytes with CBOM data.
/// </summary>
public static byte[] InjectCbomBytes(
byte[] cycloneDxJsonBytes,
ImmutableDictionary<string, ImmutableArray<CryptoAsset>> cryptoAssetsByComponent)
{
var json = System.Text.Encoding.UTF8.GetString(cycloneDxJsonBytes);
var enhanced = InjectCbom(json, cryptoAssetsByComponent);
return System.Text.Encoding.UTF8.GetBytes(enhanced);
}
private static JsonArray? BuildCryptoProperties(ImmutableArray<CryptoAsset> assets)
{
if (assets.IsDefaultOrEmpty)
return null;
var cryptoArray = new JsonArray();
foreach (var asset in assets)
{
var cryptoObj = new JsonObject
{
["assetType"] = MapAssetType(asset.AssetType)
};
// Add OID if present
if (!string.IsNullOrEmpty(asset.Oid))
{
cryptoObj["oid"] = asset.Oid;
}
// Build algorithm properties
if (asset.AssetType == CryptoAssetType.Algorithm)
{
var algProps = BuildAlgorithmProperties(asset);
if (algProps != null)
{
cryptoObj["algorithmProperties"] = algProps;
}
}
// Build related crypto material properties
else if (asset.AssetType == CryptoAssetType.RelatedCryptoMaterial && asset.CryptoProperties?.RelatedCryptoMaterialProperties != null)
{
var matProps = BuildRelatedCryptoMaterialProperties(asset.CryptoProperties.RelatedCryptoMaterialProperties);
if (matProps != null)
{
cryptoObj["relatedCryptoMaterialProperties"] = matProps;
}
}
// Build certificate properties
else if (asset.AssetType == CryptoAssetType.Certificate && asset.CryptoProperties?.CertificateProperties != null)
{
var certProps = BuildCertificateProperties(asset.CryptoProperties.CertificateProperties);
if (certProps != null)
{
cryptoObj["certificateProperties"] = certProps;
}
}
// Build protocol properties
else if (asset.AssetType == CryptoAssetType.Protocol && asset.CryptoProperties?.ProtocolProperties != null)
{
var protoProps = BuildProtocolProperties(asset.CryptoProperties.ProtocolProperties);
if (protoProps != null)
{
cryptoObj["protocolProperties"] = protoProps;
}
}
cryptoArray.Add(cryptoObj);
}
return cryptoArray.Count > 0 ? cryptoArray : null;
}
private static JsonObject? BuildAlgorithmProperties(CryptoAsset asset)
{
var props = new JsonObject();
// Primitive
if (asset.Primitive.HasValue)
{
props["primitive"] = MapPrimitive(asset.Primitive.Value);
}
// Crypto functions
if (!asset.Functions.IsDefaultOrEmpty)
{
var funcsArray = new JsonArray();
foreach (var func in asset.Functions)
{
funcsArray.Add(MapFunction(func));
}
props["cryptoFunctions"] = funcsArray;
}
// Mode
if (asset.Mode.HasValue)
{
props["mode"] = MapMode(asset.Mode.Value);
}
// Padding
if (asset.Padding.HasValue)
{
props["padding"] = MapPadding(asset.Padding.Value);
}
// Curve
if (!string.IsNullOrEmpty(asset.Curve))
{
props["curve"] = asset.Curve;
}
// Key size as parameter set identifier
if (asset.KeySizeBits.HasValue)
{
props["parameterSetIdentifier"] = $"{asset.KeySizeBits.Value}";
props["classicalSecurityLevel"] = asset.KeySizeBits.Value;
}
// Execution environment
if (asset.ExecutionEnvironment.HasValue)
{
props["executionEnvironment"] = MapExecutionEnvironment(asset.ExecutionEnvironment.Value);
}
// Implementation platform
if (!string.IsNullOrEmpty(asset.ImplementationPlatform))
{
props["implementationPlatform"] = asset.ImplementationPlatform;
}
// Check for post-quantum and add NIST security level
if (IsPostQuantumAlgorithm(asset.AlgorithmName))
{
// Typical NIST level for ML-KEM/ML-DSA is 1, 3, or 5
props["nistQuantumSecurityLevel"] = GetNistQuantumLevel(asset.AlgorithmName);
}
return props.Count > 0 ? props : null;
}
private static JsonObject? BuildRelatedCryptoMaterialProperties(RelatedCryptoMaterialProperties material)
{
var props = new JsonObject();
if (material.Type.HasValue)
{
props["type"] = MapRelatedMaterialType(material.Type.Value);
}
if (!string.IsNullOrEmpty(material.Id))
{
props["id"] = material.Id;
}
if (material.State.HasValue)
{
props["state"] = MapMaterialState(material.State.Value);
}
if (material.Size.HasValue)
{
props["size"] = material.Size.Value;
}
if (!string.IsNullOrEmpty(material.AlgorithmRef))
{
props["algorithmRef"] = material.AlgorithmRef;
}
if (!string.IsNullOrEmpty(material.CreationDate))
{
props["creationDate"] = material.CreationDate;
}
if (!string.IsNullOrEmpty(material.ActivationDate))
{
props["activationDate"] = material.ActivationDate;
}
if (!string.IsNullOrEmpty(material.ExpirationDate))
{
props["expirationDate"] = material.ExpirationDate;
}
if (!string.IsNullOrEmpty(material.Format))
{
props["format"] = material.Format;
}
return props.Count > 0 ? props : null;
}
private static JsonObject? BuildCertificateProperties(CertificateProperties cert)
{
var props = new JsonObject();
if (!string.IsNullOrEmpty(cert.SubjectName))
{
props["subjectName"] = cert.SubjectName;
}
if (!string.IsNullOrEmpty(cert.IssuerName))
{
props["issuerName"] = cert.IssuerName;
}
if (!string.IsNullOrEmpty(cert.NotValidBefore))
{
props["notValidBefore"] = cert.NotValidBefore;
}
if (!string.IsNullOrEmpty(cert.NotValidAfter))
{
props["notValidAfter"] = cert.NotValidAfter;
}
if (!string.IsNullOrEmpty(cert.SignatureAlgorithmRef))
{
props["signatureAlgorithmRef"] = cert.SignatureAlgorithmRef;
}
if (!string.IsNullOrEmpty(cert.SubjectPublicKeyRef))
{
props["subjectPublicKeyRef"] = cert.SubjectPublicKeyRef;
}
if (cert.CertificateFormat.HasValue)
{
props["certificateFormat"] = MapCertificateFormat(cert.CertificateFormat.Value);
}
return props.Count > 0 ? props : null;
}
private static JsonObject? BuildProtocolProperties(ProtocolProperties protocol)
{
var props = new JsonObject();
if (protocol.Type.HasValue)
{
props["type"] = MapProtocolType(protocol.Type.Value);
}
if (!string.IsNullOrEmpty(protocol.Version))
{
props["version"] = protocol.Version;
}
if (!protocol.CipherSuites.IsDefaultOrEmpty)
{
var suitesArray = new JsonArray();
foreach (var suite in protocol.CipherSuites)
{
var suiteObj = new JsonObject();
if (!string.IsNullOrEmpty(suite.Name))
{
suiteObj["name"] = suite.Name;
}
if (!suite.Algorithms.IsDefaultOrEmpty)
{
var algsArray = new JsonArray();
foreach (var alg in suite.Algorithms)
{
algsArray.Add(alg);
}
suiteObj["algorithms"] = algsArray;
}
suitesArray.Add(suiteObj);
}
props["cipherSuites"] = suitesArray;
}
return props.Count > 0 ? props : null;
}
private static string MapAssetType(CryptoAssetType type) => type switch
{
CryptoAssetType.Algorithm => "algorithm",
CryptoAssetType.Certificate => "certificate",
CryptoAssetType.Protocol => "protocol",
CryptoAssetType.RelatedCryptoMaterial => "related-crypto-material",
_ => "unknown"
};
private static string MapPrimitive(CryptoPrimitive primitive) => primitive switch
{
CryptoPrimitive.Dlog => "dlog",
CryptoPrimitive.Ec => "ec",
CryptoPrimitive.Rsa => "rsa",
CryptoPrimitive.Lattice => "lattice",
CryptoPrimitive.Hash => "hash",
CryptoPrimitive.BlockCipher => "block-cipher",
CryptoPrimitive.StreamCipher => "stream-cipher",
CryptoPrimitive.Aead => "aead",
CryptoPrimitive.Mac => "mac",
CryptoPrimitive.Kdf => "kdf",
CryptoPrimitive.Kem => "kem",
CryptoPrimitive.Pbkdf => "pbkdf",
CryptoPrimitive.Signature => "signature",
CryptoPrimitive.KeyAgree => "key-agree",
CryptoPrimitive.Prng => "prng",
_ => "other"
};
private static string MapFunction(CryptoFunction func) => func switch
{
CryptoFunction.Generate => "generate",
CryptoFunction.Keygen => "keygen",
CryptoFunction.Derive => "derive",
CryptoFunction.Sign => "sign",
CryptoFunction.Verify => "verify",
CryptoFunction.Encrypt => "encrypt",
CryptoFunction.Decrypt => "decrypt",
CryptoFunction.Encapsulate => "encapsulate",
CryptoFunction.Decapsulate => "decapsulate",
CryptoFunction.Digest => "digest",
CryptoFunction.Tag => "tag",
CryptoFunction.KeyWrap => "key-wrap",
CryptoFunction.KeyUnwrap => "key-unwrap",
CryptoFunction.KeyAgree => "key-agree",
_ => "other"
};
private static string MapMode(CryptoMode mode) => mode switch
{
CryptoMode.Cbc => "cbc",
CryptoMode.Ecb => "ecb",
CryptoMode.Ccm => "ccm",
CryptoMode.Gcm => "gcm",
CryptoMode.Cfb => "cfb",
CryptoMode.Ofb => "ofb",
CryptoMode.Ctr => "ctr",
CryptoMode.Xts => "xts",
CryptoMode.Wrap => "wrap",
_ => "other"
};
private static string MapPadding(CryptoPadding padding) => padding switch
{
CryptoPadding.Pkcs7 => "pkcs7",
CryptoPadding.Oaep => "oaep",
CryptoPadding.Pkcs1v15 => "pkcs1v15",
CryptoPadding.Pss => "pss",
CryptoPadding.X923 => "x923",
CryptoPadding.Raw => "raw",
CryptoPadding.None => "none",
_ => "other"
};
private static string MapExecutionEnvironment(ExecutionEnvironment env) => env switch
{
ExecutionEnvironment.Software => "software",
ExecutionEnvironment.HardwareSecurityModule => "hardware-security-module",
ExecutionEnvironment.TrustedExecutionEnvironment => "trusted-execution-environment",
ExecutionEnvironment.Hardware => "hardware",
_ => "unknown"
};
private static string MapRelatedMaterialType(RelatedCryptoMaterialType type) => type switch
{
RelatedCryptoMaterialType.PrivateKey => "private-key",
RelatedCryptoMaterialType.PublicKey => "public-key",
RelatedCryptoMaterialType.SecretKey => "secret-key",
RelatedCryptoMaterialType.Key => "key",
RelatedCryptoMaterialType.Nonce => "nonce",
RelatedCryptoMaterialType.Seed => "seed",
RelatedCryptoMaterialType.Iv => "iv",
RelatedCryptoMaterialType.Salt => "salt",
RelatedCryptoMaterialType.SharedSecret => "shared-secret",
_ => "other"
};
private static string MapMaterialState(CryptoMaterialState state) => state switch
{
CryptoMaterialState.PreActivation => "pre-activation",
CryptoMaterialState.Active => "active",
CryptoMaterialState.Suspended => "suspended",
CryptoMaterialState.Deactivated => "deactivated",
CryptoMaterialState.Compromised => "compromised",
CryptoMaterialState.Destroyed => "destroyed",
_ => "unknown"
};
private static string MapCertificateFormat(CertificateFormat format) => format switch
{
CertificateFormat.X509 => "X.509",
CertificateFormat.Pgp => "PGP",
CertificateFormat.Pkcs7 => "PKCS#7",
_ => "other"
};
private static string MapProtocolType(ProtocolType type) => type switch
{
ProtocolType.Tls => "tls",
ProtocolType.Ssh => "ssh",
ProtocolType.Ipsec => "ipsec",
ProtocolType.Ike => "ike",
ProtocolType.Sstp => "sstp",
ProtocolType.Wpa => "wpa",
_ => "other"
};
private static bool IsPostQuantumAlgorithm(string? algorithmName)
{
if (string.IsNullOrEmpty(algorithmName))
return false;
var upper = algorithmName.ToUpperInvariant();
return upper.Contains("KYBER") || upper.Contains("ML-KEM") ||
upper.Contains("DILITHIUM") || upper.Contains("ML-DSA") ||
upper.Contains("SPHINCS") || upper.Contains("SLH-DSA") ||
upper.Contains("FALCON") || upper.Contains("NTRU") ||
upper.Contains("FRODO") || upper.Contains("SABER");
}
private static int GetNistQuantumLevel(string? algorithmName)
{
if (string.IsNullOrEmpty(algorithmName))
return 1;
var upper = algorithmName.ToUpperInvariant();
// ML-KEM-768 / Dilithium3 => Level 3
// ML-KEM-1024 / Dilithium5 => Level 5
if (upper.Contains("1024") || upper.Contains("5"))
return 5;
if (upper.Contains("768") || upper.Contains("3"))
return 3;
// Default to Level 1 (ML-KEM-512 / Dilithium2)
return 1;
}
}