mirror of
https://github.com/wanghongenpin/proxypin.git
synced 2026-05-18 16:06:50 +08:00
x509
This commit is contained in:
@@ -20,8 +20,10 @@ import 'dart:math';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:basic_utils/basic_utils.dart';
|
||||
import 'package:network_proxy/network/util/x509.dart';
|
||||
import 'package:network_proxy/network/util/x509/basic_constraints.dart';
|
||||
import 'package:network_proxy/network/util/x509/x509.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:network_proxy/network/util/x509/key_usage.dart' as x509;
|
||||
|
||||
import 'file_read.dart';
|
||||
|
||||
@@ -95,10 +97,7 @@ class CertificateManager {
|
||||
x509Subject['CN'] = host;
|
||||
|
||||
var csrPem = X509Generate.generateSelfSignedCertificate(caRoot, serverPubKey, caPriKey, 365,
|
||||
extKeyUsage: [ExtendedKeyUsage.SERVER_AUTH],
|
||||
sans: [host],
|
||||
serialNumber: Random().nextInt(1000000).toString(),
|
||||
subject: x509Subject);
|
||||
sans: [host], serialNumber: Random().nextInt(1000000).toString(), subject: x509Subject);
|
||||
return csrPem;
|
||||
}
|
||||
|
||||
@@ -122,7 +121,18 @@ class CertificateManager {
|
||||
};
|
||||
x509Subject['CN'] = 'ProxyPin CA (${Platform.localHostname})';
|
||||
|
||||
var csrPem = generate(_caCert, serverPubKey, serverPriKey, 'ProxyPin CA (${Platform.localHostname})');
|
||||
var csrPem = X509Generate.generateSelfSignedCertificate(
|
||||
_caCert,
|
||||
serverPubKey,
|
||||
serverPriKey,
|
||||
825,
|
||||
sans: [x509Subject['CN']!],
|
||||
serialNumber: Random().nextInt(1000000).toString(),
|
||||
subject: x509Subject,
|
||||
keyUsage: x509.KeyUsage(x509.KeyUsage.keyCertSign | x509.KeyUsage.cRLSign),
|
||||
extKeyUsage: [ExtendedKeyUsage.SERVER_AUTH, ExtendedKeyUsage.CLIENT_AUTH],
|
||||
basicConstraints: BasicConstraints(isCA: true),
|
||||
);
|
||||
|
||||
//重新写入根证书
|
||||
var caFile = await certificateFile();
|
||||
|
||||
9
lib/network/util/x509/basic_constraints.dart
Normal file
9
lib/network/util/x509/basic_constraints.dart
Normal file
@@ -0,0 +1,9 @@
|
||||
/// @author wanghongen
|
||||
/// 2024/7/28
|
||||
class BasicConstraints {
|
||||
final bool isCA;
|
||||
final int? pathLenConstraint;
|
||||
final bool critical;
|
||||
|
||||
BasicConstraints({required this.isCA, this.pathLenConstraint, this.critical = true});
|
||||
}
|
||||
23
lib/network/util/x509/extension.dart
Normal file
23
lib/network/util/x509/extension.dart
Normal file
@@ -0,0 +1,23 @@
|
||||
import 'package:pointycastle/pointycastle.dart';
|
||||
|
||||
/// an object for the elements in the X.509 V3 extension block.
|
||||
class Extension {
|
||||
/// Key Usage
|
||||
static final ASN1ObjectIdentifier keyUsage = ASN1ObjectIdentifier.fromIdentifierString("2.5.29.15");
|
||||
|
||||
/// Subject Alternative Name
|
||||
static final ASN1ObjectIdentifier subjectAlternativeName = ASN1ObjectIdentifier.fromIdentifierString("2.5.29.17");
|
||||
|
||||
/// Basic Constraints
|
||||
static final ASN1ObjectIdentifier basicConstraints = ASN1ObjectIdentifier.fromIdentifierString("2.5.29.19");
|
||||
|
||||
/// Extended Key Usage
|
||||
static final ASN1ObjectIdentifier extendedKeyUsage = ASN1ObjectIdentifier.fromIdentifierString("2.5.29.37");
|
||||
|
||||
final ASN1ObjectIdentifier extnId;
|
||||
final bool critical;
|
||||
|
||||
final ASN1OctetString value;
|
||||
|
||||
Extension(this.extnId, this.critical, this.value);
|
||||
}
|
||||
39
lib/network/util/x509/key_usage.dart
Normal file
39
lib/network/util/x509/key_usage.dart
Normal file
@@ -0,0 +1,39 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:pointycastle/pointycastle.dart';
|
||||
|
||||
class KeyUsage {
|
||||
static const int digitalSignature = (1 << 7);
|
||||
static const int nonRepudiation = (1 << 6);
|
||||
static const int keyEncipherment = (1 << 5);
|
||||
static const int dataEncipherment = (1 << 4);
|
||||
static const int keyAgreement = (1 << 3);
|
||||
static const int keyCertSign = (1 << 2);
|
||||
static const int cRLSign = (1 << 1);
|
||||
static const int encipherOnly = (1 << 0);
|
||||
static const int decipherOnly = (1 << 15);
|
||||
|
||||
final ASN1BitString bitString;
|
||||
final bool critical;
|
||||
|
||||
KeyUsage(int usage, {this.critical = true}) : bitString = ASN1BitString.fromBytes(keyUsageBytes(usage));
|
||||
|
||||
static Uint8List keyUsageBytes(int valueBytes) {
|
||||
var bytes = [valueBytes];
|
||||
if (valueBytes > 0xFF) {
|
||||
final int firstValueByte = (valueBytes & int.parse("ff00", radix: 16)) >> 8;
|
||||
final int secondValueByte = (valueBytes & int.parse("00ff", radix: 16));
|
||||
bytes = [firstValueByte, secondValueByte];
|
||||
}
|
||||
|
||||
return Uint8List.fromList(<int>[
|
||||
// BitString identifier
|
||||
3,
|
||||
// Length
|
||||
bytes.length + 1,
|
||||
// Unused bytes at the end
|
||||
1,
|
||||
...bytes
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -4,9 +4,13 @@ import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:basic_utils/basic_utils.dart';
|
||||
import 'package:network_proxy/network/util/x509/extension.dart';
|
||||
import 'package:network_proxy/network/util/x509/key_usage.dart' as x509;
|
||||
import 'package:pointycastle/asn1/unsupported_object_identifier_exception.dart';
|
||||
import 'package:pointycastle/pointycastle.dart';
|
||||
|
||||
import 'basic_constraints.dart';
|
||||
|
||||
/// @author wanghongen
|
||||
/// 2023/7/26
|
||||
class X509Generate {
|
||||
@@ -38,7 +42,9 @@ class X509Generate {
|
||||
String serialNumber = '1',
|
||||
Map<String, String>? issuer,
|
||||
Map<String, String>? subject,
|
||||
x509.KeyUsage? keyUsage,
|
||||
List<ExtendedKeyUsage>? extKeyUsage,
|
||||
BasicConstraints? basicConstraints,
|
||||
}) {
|
||||
var data = ASN1Sequence();
|
||||
|
||||
@@ -87,18 +93,34 @@ class X509Generate {
|
||||
data.add(_makePublicKeyBlock(publicKey));
|
||||
|
||||
// Add Extensions
|
||||
if (IterableUtils.isNotNullOrEmpty(sans) || IterableUtils.isNotNullOrEmpty(extKeyUsage)) {
|
||||
|
||||
if (IterableUtils.isNotNullOrEmpty(sans) || keyUsage != null || IterableUtils.isNotNullOrEmpty(extKeyUsage)) {
|
||||
var extensionTopSequence = ASN1Sequence();
|
||||
|
||||
// Add Key Usage
|
||||
var extKeyUsageSequence = extKeyEncodings(extKeyUsage);
|
||||
if (extKeyUsageSequence != null) {
|
||||
extensionTopSequence.add(extKeyUsageSequence);
|
||||
// Add basic constraints 2.5.29.19
|
||||
if (basicConstraints != null) {
|
||||
var basicConstraintsValue = ASN1Sequence();
|
||||
basicConstraintsValue.add(ASN1Boolean(basicConstraints.isCA));
|
||||
if (basicConstraints.pathLenConstraint != null) {
|
||||
basicConstraintsValue.add(ASN1Integer(BigInt.from(basicConstraints.pathLenConstraint!)));
|
||||
}
|
||||
var octetString = ASN1OctetString(octets: basicConstraintsValue.encode());
|
||||
var basicConstraintsSequence = ASN1Sequence();
|
||||
basicConstraintsSequence.add(Extension.basicConstraints);
|
||||
if (basicConstraints.critical) {
|
||||
basicConstraintsSequence.add(ASN1Boolean(true));
|
||||
}
|
||||
basicConstraintsSequence.add(octetString);
|
||||
extensionTopSequence.add(basicConstraintsSequence);
|
||||
}
|
||||
|
||||
if (IterableUtils.isNotNullOrEmpty(sans)) {
|
||||
var extensionTopSequence = ASN1Sequence();
|
||||
// Add key usage 2.5.29.15
|
||||
if (keyUsage != null) {
|
||||
extensionTopSequence.add(keyUsageSequence(keyUsage)!);
|
||||
}
|
||||
|
||||
//2.5.29.17
|
||||
if (IterableUtils.isNotNullOrEmpty(sans)) {
|
||||
var sanList = ASN1Sequence();
|
||||
for (var s in sans!) {
|
||||
sanList.add(ASN1PrintableString(stringValue: s, tag: 0x82));
|
||||
@@ -106,15 +128,21 @@ class X509Generate {
|
||||
var octetString = ASN1OctetString(octets: sanList.encode());
|
||||
|
||||
var sanSequence = ASN1Sequence();
|
||||
sanSequence.add(ASN1ObjectIdentifier.fromIdentifierString('2.5.29.17'));
|
||||
sanSequence.add(Extension.subjectAlternativeName);
|
||||
sanSequence.add(octetString);
|
||||
extensionTopSequence.add(sanSequence);
|
||||
|
||||
var extObj = ASN1Object(tag: 0xA3);
|
||||
extObj.valueBytes = extensionTopSequence.encode();
|
||||
|
||||
data.add(extObj);
|
||||
}
|
||||
|
||||
// Add ext key usage 2.5.29.37
|
||||
var extKeyUsageSequence = extendedKeyUsageEncodings(extKeyUsage);
|
||||
if (extKeyUsageSequence != null) {
|
||||
extensionTopSequence.add(extKeyUsageSequence);
|
||||
}
|
||||
|
||||
var extObj = ASN1Object(tag: 0xA3);
|
||||
extObj.valueBytes = extensionTopSequence.encode();
|
||||
|
||||
data.add(extObj);
|
||||
}
|
||||
|
||||
var outer = ASN1Sequence();
|
||||
@@ -128,7 +156,20 @@ class X509Generate {
|
||||
return '$BEGIN_CERT\n${chunks.join('\r\n')}\n$END_CERT';
|
||||
}
|
||||
|
||||
static ASN1Sequence? extKeyEncodings(List<ExtendedKeyUsage>? extKeyUsage) {
|
||||
static ASN1Sequence? keyUsageSequence(x509.KeyUsage keyUsages) {
|
||||
var octetString = ASN1OctetString(octets: keyUsages.bitString.encode());
|
||||
|
||||
var keyUsageSequence = ASN1Sequence();
|
||||
keyUsageSequence.add(Extension.keyUsage);
|
||||
if (keyUsages.critical) {
|
||||
keyUsageSequence.add(ASN1Boolean(true));
|
||||
}
|
||||
keyUsageSequence.add(octetString);
|
||||
|
||||
return keyUsageSequence;
|
||||
}
|
||||
|
||||
static ASN1Sequence? extendedKeyUsageEncodings(List<ExtendedKeyUsage>? extKeyUsage) {
|
||||
if (IterableUtils.isNullOrEmpty(extKeyUsage)) {
|
||||
return null;
|
||||
}
|
||||
@@ -165,7 +206,7 @@ class X509Generate {
|
||||
var octetString = ASN1OctetString(octets: extKeyUsageList.encode());
|
||||
|
||||
var extKeyUsageSequence = ASN1Sequence();
|
||||
extKeyUsageSequence.add(ASN1ObjectIdentifier.fromIdentifierString('2.5.29.37'));
|
||||
extKeyUsageSequence.add(Extension.extendedKeyUsage);
|
||||
extKeyUsageSequence.add(octetString);
|
||||
return extKeyUsageSequence;
|
||||
}
|
||||
@@ -92,6 +92,7 @@ class _SslState extends State<SslWidget> {
|
||||
child: Text(localizations.exportCaP12, style: const TextStyle(fontSize: 14))),
|
||||
onPressed: () async {
|
||||
//show p12 password
|
||||
String? password;
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
@@ -101,11 +102,11 @@ class _SslState extends State<SslWidget> {
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: TextField(
|
||||
controller: TextEditingController(),
|
||||
decoration: const InputDecoration(
|
||||
hintText: "Enter a password to protect p12 file",
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
onChanged: (val) => password = val,
|
||||
),
|
||||
),
|
||||
Row(mainAxisAlignment: MainAxisAlignment.end, children: [
|
||||
@@ -115,8 +116,8 @@ class _SslState extends State<SslWidget> {
|
||||
String? path = (await getSaveLocation(suggestedName: "ProxyPinPkcs12.p12"))?.path;
|
||||
if (path == null) return;
|
||||
|
||||
var password = TextEditingController().text;
|
||||
var p12Bytes = await CertificateManager.generatePkcs12(password);
|
||||
var p12Bytes = await CertificateManager.generatePkcs12(
|
||||
password?.isNotEmpty == true ? password : null);
|
||||
await File(path).writeAsBytes(p12Bytes);
|
||||
if (context.mounted) Navigator.pop(context);
|
||||
},
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:basic_utils/basic_utils.dart';
|
||||
import 'package:network_proxy/network/util/x509.dart';
|
||||
import 'package:network_proxy/network/util/x509/basic_constraints.dart';
|
||||
import 'package:network_proxy/network/util/x509/key_usage.dart' as x509;
|
||||
import 'package:network_proxy/network/util/x509/x509.dart';
|
||||
|
||||
void main() async {
|
||||
var caPem = await File('assets/certs/ca.crt').readAsString();
|
||||
@@ -11,33 +14,55 @@ void main() async {
|
||||
var serverPubKey = generateRSAKeyPair.publicKey as RSAPublicKey;
|
||||
var serverPriKey = generateRSAKeyPair.privateKey as RSAPrivateKey;
|
||||
|
||||
print(CryptoUtils.encodeRSAPublicKeyToPem(serverPubKey));
|
||||
//保存私钥
|
||||
var serverPriKeyPem = CryptoUtils.encodeRSAPrivateKeyToPem(serverPriKey);
|
||||
print(serverPriKeyPem);
|
||||
await File('assets/certs/server.key').writeAsString(serverPriKeyPem);
|
||||
var rsaPrivateKeyFromPem = CryptoUtils.rsaPrivateKeyFromPem(serverPriKeyPem);
|
||||
print(rsaPrivateKeyFromPem);
|
||||
var crt = generate(caRoot, serverPubKey, serverPriKey);
|
||||
var serverPublicKeyPem = """-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqVXqbCErPZMS+2Eb3MUT
|
||||
eTNIYZHoCMZk5gFIo3pD70dZimQj2yMBIh9Rq4rO0/Dj9zt52vR1zbxDnmx/5TDC
|
||||
djDHk/zHYW66VLYCo4n1H4/dddFvJ8Y8syBNpa+seSAR6ljF807gZqINGeNKi8Du
|
||||
N82XiED2Ix3woE1jMQfP3E16alxHaejFBZ77SUOXJhJDM5SKD2H0bxGw9cVw9K69
|
||||
NmnZMIM9+U8+TuM9EzvMUuHTY278Ov72c9HpO5OAx2zfyXGlmUGgyUCiYnxeATX5
|
||||
LceGVEoT2MWhFibWvPBpH315xNXU57dWKWW714tPsvzzNHzKZspz/LQ36fU9goUg
|
||||
NQIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
""";
|
||||
print(serverPublicKeyPem);
|
||||
var readAsString = await File('assets/certs/server.key').readAsString();
|
||||
// var rsaPrivateKeyFromPem = CryptoUtils.rsaPrivateKeyFromPem(serverPriKeyPem);
|
||||
// print(rsaPrivateKeyFromPem);
|
||||
var crt = generate(
|
||||
caRoot, CryptoUtils.rsaPublicKeyFromPem(serverPublicKeyPem), CryptoUtils.rsaPrivateKeyFromPem(readAsString));
|
||||
print(crt);
|
||||
|
||||
await File('assets/certs/server.crt').writeAsString(crt);
|
||||
//TLS服务器证书必须包含ExtendedKeyUsage(EKU)扩展,该扩展包含id-kp-serverAuth OID。
|
||||
X509Utils.generateSelfSignedCertificate(serverPriKey, CryptoUtils.encodeRSAPublicKeyToPem(serverPubKey), 825,
|
||||
serialNumber: Random().nextInt(1000000).toString(),
|
||||
issuer: {
|
||||
'C': 'CN',
|
||||
'ST': 'BJ',
|
||||
'L': 'Beijing',
|
||||
'O': 'Proxy',
|
||||
'OU': 'ProxyPin',
|
||||
'CN': 'ProxyPin CA (${Platform.localHostname})'
|
||||
},
|
||||
extKeyUsage: [
|
||||
ExtendedKeyUsage.SERVER_AUTH
|
||||
]);
|
||||
// await File('assets/certs/server.crt').writeAsString(crt);
|
||||
// var readAsString2 = File('assets/certs/server.crt').readAsStringSync();
|
||||
|
||||
var generatePkcs12 = Pkcs12Utils.generatePkcs12(serverPriKeyPem, [crt], password: '123456');
|
||||
await File('C:\\Users\\wanghongen\\Downloads\\server.p12').writeAsBytes(generatePkcs12);
|
||||
//TLS服务器证书必须包含ExtendedKeyUsage(EKU)扩展,该扩展包含id-kp-serverAuth OID。
|
||||
|
||||
// X509Utils.generateSelfSignedCertificate(serverPriKey, caPem, 825,
|
||||
// serialNumber: Random().nextInt(1000000).toString(),
|
||||
// sans: [
|
||||
// 'ProxyPin CA (${Platform.localHostname})'
|
||||
// ],
|
||||
// issuer: {
|
||||
// 'C': 'CN',
|
||||
// 'ST': 'BJ',
|
||||
// 'L': 'Beijing',
|
||||
// 'O': 'Proxy',
|
||||
// 'OU': 'ProxyPin',
|
||||
// 'CN': 'ProxyPin CA (${Platform.localHostname})'
|
||||
// },
|
||||
// keyUsage: [
|
||||
// KeyUsage.DIGITAL_SIGNATURE,
|
||||
// KeyUsage.KEY_CERT_SIGN,
|
||||
// KeyUsage.CRL_SIGN
|
||||
// ],
|
||||
// extKeyUsage: [
|
||||
// ExtendedKeyUsage.SERVER_AUTH
|
||||
// ]);
|
||||
|
||||
var generatePkcs12 = Pkcs12Utils.generatePkcs12(readAsString, [crt], password: '123');
|
||||
await File('/Users/wanghongen/Downloads/server.p12').writeAsBytes(generatePkcs12);
|
||||
}
|
||||
|
||||
/// 生成证书
|
||||
@@ -50,10 +75,12 @@ String generate(X509CertificateData caRoot, RSAPublicKey serverPubKey, RSAPrivat
|
||||
'O': 'Proxy',
|
||||
'OU': 'ProxyPin',
|
||||
};
|
||||
x509Subject['CN'] = 'ProxyPin CA (${Platform.localHostname})';
|
||||
x509Subject['CN'] = 'ProxyPin CA (wanghongen)';
|
||||
|
||||
var csrPem = X509Generate.generateSelfSignedCertificate(caRoot, serverPubKey, caPriKey, 825,
|
||||
var csrPem = X509Generate.generateSelfSignedCertificate(caRoot, serverPubKey, caPriKey, 365,
|
||||
keyUsage: x509.KeyUsage(x509.KeyUsage.keyCertSign | x509.KeyUsage.cRLSign),
|
||||
extKeyUsage: [ExtendedKeyUsage.SERVER_AUTH],
|
||||
basicConstraints: BasicConstraints(isCA: true),
|
||||
sans: [x509Subject['CN']!],
|
||||
serialNumber: Random().nextInt(1000000).toString(),
|
||||
subject: x509Subject);
|
||||
|
||||
236
test/x509_test.dart
Normal file
236
test/x509_test.dart
Normal file
@@ -0,0 +1,236 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:basic_utils/basic_utils.dart';
|
||||
import 'package:network_proxy/network/util/x509/basic_constraints.dart';
|
||||
import 'package:pointycastle/pointycastle.dart';
|
||||
|
||||
void main() {
|
||||
encoding();
|
||||
// Add ext key usage 2.5.29.37
|
||||
// // Add key usage 2.5.29.15
|
||||
// var keyUsage = [KeyUsage.KEY_CERT_SIGN, KeyUsage.CRL_SIGN];
|
||||
//
|
||||
// var encode = keyUsageSequence(keyUsage)?.encode();
|
||||
// print(Int8List.view(encode!.buffer));
|
||||
}
|
||||
|
||||
void encoding() {
|
||||
var basicConstraints = BasicConstraints(isCA: true);
|
||||
|
||||
var extensionTopSequence = ASN1Sequence();
|
||||
|
||||
// Add basic constraints 2.5.29.19
|
||||
var basicConstraintsValue = ASN1Sequence();
|
||||
basicConstraintsValue.add(ASN1Boolean(basicConstraints.isCA));
|
||||
if (basicConstraints.pathLenConstraint != null) {
|
||||
basicConstraintsValue.add(ASN1Integer(BigInt.from(basicConstraints.pathLenConstraint!)));
|
||||
}
|
||||
|
||||
var octetString = ASN1OctetString(octets: basicConstraintsValue.encode());
|
||||
var basicConstraintsSequence = ASN1Sequence();
|
||||
basicConstraintsSequence.add(ASN1ObjectIdentifier.fromIdentifierString('2.5.29.19'));
|
||||
if (basicConstraints.critical) {
|
||||
basicConstraintsSequence.add(ASN1Boolean(true));
|
||||
}
|
||||
basicConstraintsSequence.add(octetString);
|
||||
extensionTopSequence.add(basicConstraintsSequence);
|
||||
|
||||
// Add key usage 2.5.29.15
|
||||
var keyUsage = [KeyUsage.KEY_CERT_SIGN, KeyUsage.CRL_SIGN];
|
||||
extensionTopSequence.add(keyUsageSequence(keyUsage)!);
|
||||
|
||||
//2.5.29.17
|
||||
var sans = ['ProxyPin'];
|
||||
if (IterableUtils.isNotNullOrEmpty(sans)) {
|
||||
var sanList = ASN1Sequence();
|
||||
for (var s in sans) {
|
||||
sanList.add(ASN1PrintableString(stringValue: s, tag: 0x82));
|
||||
}
|
||||
var octetString = ASN1OctetString(octets: sanList.encode());
|
||||
|
||||
var sanSequence = ASN1Sequence();
|
||||
sanSequence.add(ASN1ObjectIdentifier.fromIdentifierString('2.5.29.17'));
|
||||
sanSequence.add(octetString);
|
||||
extensionTopSequence.add(sanSequence);
|
||||
}
|
||||
|
||||
// Add ext key usage 2.5.29.37
|
||||
var extKeyUsage = [ExtendedKeyUsage.SERVER_AUTH];
|
||||
var extKeyUsageSequence = extendedKeyUsageEncodings(extKeyUsage);
|
||||
if (extKeyUsageSequence != null) {
|
||||
extensionTopSequence.add(extKeyUsageSequence);
|
||||
}
|
||||
|
||||
var extObj = ASN1Object(tag: 0xA3);
|
||||
extObj.valueBytes = extensionTopSequence.encode();
|
||||
|
||||
print(Int8List.view(extensionTopSequence.encode().buffer));
|
||||
// print(Int8List.view(extObj.encode().buffer));
|
||||
}
|
||||
|
||||
void _basicConstraints() {
|
||||
var basicConstraints = BasicConstraints(isCA: true);
|
||||
var basicConstraintsValue = ASN1Sequence();
|
||||
|
||||
basicConstraintsValue.add(ASN1Boolean(basicConstraints.isCA));
|
||||
if (basicConstraints.pathLenConstraint != null) {
|
||||
basicConstraintsValue.add(ASN1Integer(BigInt.from(basicConstraints.pathLenConstraint!)));
|
||||
}
|
||||
|
||||
print(Int8List.view(basicConstraintsValue.encode().buffer));
|
||||
|
||||
var octetString = ASN1OctetString(octets: basicConstraintsValue.encode());
|
||||
print(Int8List.view(octetString.encode().buffer));
|
||||
|
||||
var basicConstraintsSequence = ASN1Sequence();
|
||||
basicConstraintsSequence.add(ASN1ObjectIdentifier.fromIdentifierString('2.5.29.19'));
|
||||
basicConstraintsSequence.add(ASN1Boolean(true));
|
||||
basicConstraintsSequence.add(octetString);
|
||||
|
||||
print(Int8List.view(basicConstraintsSequence.encode().buffer));
|
||||
//[48, 15, 6, 3, 85, 29, 19, 1, 1, -1, 4, 5, 48, 3, 1, 1, -1]
|
||||
}
|
||||
|
||||
// class KeyUsage {
|
||||
// static const int keyCertSign = (1 << 2);
|
||||
// static const int cRLSign = (1 << 1);
|
||||
//
|
||||
// final ASN1BitString bitString;
|
||||
//
|
||||
// KeyUsage(int usage) : bitString = ASN1BitString(stringValues: getBytes(usage))..unusedbits = getPadBits(usage);
|
||||
//
|
||||
// static Uint8List getBytes(int bitString) {
|
||||
// if (bitString == 0) {
|
||||
// return Uint8List(0);
|
||||
// }
|
||||
//
|
||||
// int bytes = 4;
|
||||
// for (int i = 3; i >= 1; i--) {
|
||||
// if ((bitString & (0xFF << (i * 8))) != 0) {
|
||||
// break;
|
||||
// }
|
||||
// bytes--;
|
||||
// }
|
||||
//
|
||||
// Uint8List result = Uint8List(bytes);
|
||||
// for (int i = 0; i < bytes; i++) {
|
||||
// result[i] = ((bitString >> (i * 8)) & 0xFF);
|
||||
// }
|
||||
//
|
||||
// return result;
|
||||
// }
|
||||
//
|
||||
// static int getPadBits(int bitString) {
|
||||
// int val = 0;
|
||||
// for (int i = 3; i >= 0; i--) {
|
||||
// if (i != 0) {
|
||||
// if ((bitString >> (i * 8)) != 0) {
|
||||
// val = (bitString >> (i * 8)) & 0xFF;
|
||||
// break;
|
||||
// }
|
||||
// } else {
|
||||
// if (bitString != 0) {
|
||||
// val = bitString & 0xFF;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (val == 0) {
|
||||
// return 0;
|
||||
// }
|
||||
//
|
||||
// int bits = 1;
|
||||
// while (((val <<= 1) & 0xFF) != 0) {
|
||||
// bits++;
|
||||
// }
|
||||
//
|
||||
// return 8 - bits;
|
||||
// }
|
||||
// }
|
||||
|
||||
ASN1Sequence? keyUsageSequence(List<KeyUsage>? keyUsages) {
|
||||
int valueBytes = 0; // the last bit of the 2 bytes is always set
|
||||
for (KeyUsage usage in keyUsages!) {
|
||||
switch (usage) {
|
||||
case KeyUsage.KEY_CERT_SIGN:
|
||||
valueBytes |= (1 << 2);
|
||||
break;
|
||||
case KeyUsage.CRL_SIGN:
|
||||
valueBytes |= (1 << 1);
|
||||
break;
|
||||
// Add other cases as needed
|
||||
default:
|
||||
throw Error();
|
||||
}
|
||||
}
|
||||
|
||||
var bytes = [valueBytes];
|
||||
if (valueBytes > 0xFF) {
|
||||
final int firstValueByte = (valueBytes & int.parse("ff00", radix: 16)) >> 8;
|
||||
final int secondValueByte = (valueBytes & int.parse("00ff", radix: 16));
|
||||
bytes = [firstValueByte, secondValueByte];
|
||||
}
|
||||
|
||||
final Uint8List keyUsageBytes = Uint8List.fromList(<int>[
|
||||
// BitString identifier
|
||||
3,
|
||||
// Length
|
||||
bytes.length + 1,
|
||||
// Unused bytes at the end
|
||||
1,
|
||||
...bytes
|
||||
]);
|
||||
|
||||
print(keyUsageBytes);
|
||||
var octetString = ASN1OctetString(octets: ASN1BitString.fromBytes(keyUsageBytes).encode());
|
||||
|
||||
var keyUsageSequence = ASN1Sequence();
|
||||
keyUsageSequence.add(ASN1ObjectIdentifier.fromIdentifierString('2.5.29.15'));
|
||||
keyUsageSequence.add(ASN1Boolean(true));
|
||||
keyUsageSequence.add(octetString);
|
||||
|
||||
return keyUsageSequence;
|
||||
}
|
||||
|
||||
ASN1Sequence? extendedKeyUsageEncodings(List<ExtendedKeyUsage>? extKeyUsage) {
|
||||
if (IterableUtils.isNullOrEmpty(extKeyUsage)) {
|
||||
return null;
|
||||
}
|
||||
var extKeyUsageList = ASN1Sequence();
|
||||
for (var s in extKeyUsage!) {
|
||||
var oi = <int>[];
|
||||
switch (s) {
|
||||
case ExtendedKeyUsage.SERVER_AUTH:
|
||||
oi = [1, 3, 6, 1, 5, 5, 7, 3, 1];
|
||||
break;
|
||||
case ExtendedKeyUsage.CLIENT_AUTH:
|
||||
oi = [1, 3, 6, 1, 5, 5, 7, 3, 2];
|
||||
break;
|
||||
case ExtendedKeyUsage.CODE_SIGNING:
|
||||
oi = [1, 3, 6, 1, 5, 5, 7, 3, 3];
|
||||
break;
|
||||
case ExtendedKeyUsage.EMAIL_PROTECTION:
|
||||
oi = [1, 3, 6, 1, 5, 5, 7, 3, 4];
|
||||
break;
|
||||
case ExtendedKeyUsage.TIME_STAMPING:
|
||||
oi = [1, 3, 6, 1, 5, 5, 7, 3, 8];
|
||||
break;
|
||||
case ExtendedKeyUsage.OCSP_SIGNING:
|
||||
oi = [1, 3, 6, 1, 5, 5, 7, 3, 9];
|
||||
break;
|
||||
case ExtendedKeyUsage.BIMI:
|
||||
oi = [1, 3, 6, 1, 5, 5, 7, 3, 31];
|
||||
break;
|
||||
}
|
||||
|
||||
extKeyUsageList.add(ASN1ObjectIdentifier(oi));
|
||||
}
|
||||
|
||||
var octetString = ASN1OctetString(octets: extKeyUsageList.encode());
|
||||
|
||||
var extKeyUsageSequence = ASN1Sequence();
|
||||
extKeyUsageSequence.add(ASN1ObjectIdentifier.fromIdentifierString('2.5.29.37'));
|
||||
extKeyUsageSequence.add(octetString);
|
||||
return extKeyUsageSequence;
|
||||
}
|
||||
Reference in New Issue
Block a user