Skip to content

Commit be72935

Browse files
committed
WIP: ???
1 parent 8c69fad commit be72935

File tree

10 files changed

+310
-21
lines changed

10 files changed

+310
-21
lines changed

cryptography-serialization/asn1/build.gradle.kts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,7 @@ kotlin {
3434
}
3535
}
3636
}
37+
38+
//https://datatracker.ietf.org/doc/html/rfc5280
39+
//https://csrc.nist.gov/Projects/pki-testing/sample-certificates-and-crls
40+
//https://csrc.nist.gov/Projects/pki-testing/x-509-path-validation-test-suite

cryptography-serialization/asn1/modules/src/commonMain/kotlin/AlgorithmIdentifier.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
/*
2-
* Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
2+
* Copyright (c) 2024-2025 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
33
*/
44

55
package dev.whyoleg.cryptography.serialization.asn1.modules
66

77
import dev.whyoleg.cryptography.serialization.asn1.*
88

9+
// overall, this is polymorphism?
10+
// algorithm - is a type
11+
// parameters - is a value
12+
913
/**
1014
* ```
1115
* AlgorithmIdentifier ::= SEQUENCE {

cryptography-serialization/asn1/modules/src/commonMain/kotlin/EC.kt

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
2+
* Copyright (c) 2024-2025 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
33
*/
44

55
package dev.whyoleg.cryptography.serialization.asn1.modules
@@ -10,7 +10,7 @@ import dev.whyoleg.cryptography.serialization.asn1.ContextSpecificTag.*
1010
import kotlinx.serialization.*
1111
import kotlin.jvm.*
1212

13-
public val ObjectIdentifier.Companion.EC: ObjectIdentifier get() = ObjectIdentifier("1.2.840.10045.2.1")
13+
public val ObjectIdentifier.Companion.EC: ObjectIdentifier get() = ObjectIdentifier.parse("1.2.840.10045.2.1")
1414

1515
public class EcKeyAlgorithmIdentifier(
1616
override val parameters: EcParameters?,
@@ -45,6 +45,7 @@ public value class EcPoint(
4545
public class EcPrivateKey(
4646
public val version: Int,
4747
public val privateKey: ByteArray,
48+
@Asn1Tag(0, Asn1Tag.TagType.EXPLICIT)
4849
@ContextSpecificTag(0, TagType.EXPLICIT)
4950
public val parameters: EcParameters? = null,
5051
@ContextSpecificTag(1, TagType.EXPLICIT)
@@ -68,9 +69,9 @@ public value class EcParameters(
6869
public val namedCurve: ObjectIdentifier,
6970
)
7071

71-
public val ObjectIdentifier.Companion.secp256r1: ObjectIdentifier get() = ObjectIdentifier("1.2.840.10045.3.1.7")
72-
public val ObjectIdentifier.Companion.secp384r1: ObjectIdentifier get() = ObjectIdentifier("1.3.132.0.34")
73-
public val ObjectIdentifier.Companion.secp521r1: ObjectIdentifier get() = ObjectIdentifier("1.3.132.0.35")
72+
public val ObjectIdentifier.Companion.secp256r1: ObjectIdentifier get() = ObjectIdentifier.parse("1.2.840.10045.3.1.7")
73+
public val ObjectIdentifier.Companion.secp384r1: ObjectIdentifier get() = ObjectIdentifier.parse("1.3.132.0.34")
74+
public val ObjectIdentifier.Companion.secp521r1: ObjectIdentifier get() = ObjectIdentifier.parse("1.3.132.0.35")
7475

7576
/**
7677
* ```
Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
/*
2-
* Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
2+
* Copyright (c) 2024-2025 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
33
*/
44

55
package dev.whyoleg.cryptography.serialization.asn1.modules
66

77
import dev.whyoleg.cryptography.serialization.asn1.*
88
import kotlinx.serialization.*
9+
import kotlinx.serialization.descriptors.*
10+
import kotlinx.serialization.encoding.*
911

1012
@Serializable(KeyAlgorithmIdentifierSerializer::class)
1113
public interface KeyAlgorithmIdentifier : AlgorithmIdentifier
@@ -14,3 +16,39 @@ public class UnknownKeyAlgorithmIdentifier(override val algorithm: ObjectIdentif
1416
override val parameters: Nothing? get() = null
1517
}
1618

19+
// custom serializer
20+
public sealed interface KeyAlgorithmIdentifier2 {
21+
public val algorithm: ObjectIdentifier
22+
23+
public data object RSA : KeyAlgorithmIdentifier2 {
24+
override val algorithm: ObjectIdentifier get() = ObjectIdentifier.rsaEncryption
25+
}
26+
27+
public data class EC(val parameters: EcParameters?) : KeyAlgorithmIdentifier2 {
28+
override val algorithm: ObjectIdentifier get() = TODO("Not yet implemented")
29+
}
30+
31+
// those could be overridden by users
32+
public interface Unknown : KeyAlgorithmIdentifier2
33+
}
34+
35+
public val ObjectIdentifier.Companion.rsaEncryption: ObjectIdentifier get() = ObjectIdentifier.parse("1.2.840.113549.1.1.1")
36+
37+
private class RsaSer : KSerializer<KeyAlgorithmIdentifier2.RSA> {
38+
override val descriptor: SerialDescriptor
39+
get() = TODO("Not yet implemented")
40+
41+
override fun serialize(
42+
encoder: Encoder,
43+
value: KeyAlgorithmIdentifier2.RSA,
44+
) {
45+
encoder.encodeNull()
46+
}
47+
48+
override fun deserialize(decoder: Decoder): KeyAlgorithmIdentifier2.RSA {
49+
require(!decoder.decodeNotNullMark())
50+
decoder.decodeNull()
51+
// TODO?
52+
return KeyAlgorithmIdentifier2.RSA
53+
}
54+
}

cryptography-serialization/asn1/modules/src/commonMain/kotlin/RSA.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
2+
* Copyright (c) 2024-2025 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
33
*/
44

55
package dev.whyoleg.cryptography.serialization.asn1.modules
@@ -8,7 +8,7 @@ import dev.whyoleg.cryptography.bigint.*
88
import dev.whyoleg.cryptography.serialization.asn1.*
99
import kotlinx.serialization.*
1010

11-
public val ObjectIdentifier.Companion.RSA: ObjectIdentifier get() = ObjectIdentifier("1.2.840.113549.1.1.1")
11+
public val ObjectIdentifier.Companion.RSA: ObjectIdentifier get() = ObjectIdentifier.parse("1.2.840.113549.1.1.1")
1212

1313
public object RsaKeyAlgorithmIdentifier : KeyAlgorithmIdentifier {
1414
override val algorithm: ObjectIdentifier get() = ObjectIdentifier.RSA

cryptography-serialization/asn1/modules/src/commonMain/kotlin/x509.kt

Lines changed: 70 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,78 @@
55
package dev.whyoleg.cryptography.serialization.asn1.modules
66

77
import dev.whyoleg.cryptography.bigint.*
8-
import dev.whyoleg.cryptography.bits.*
98
import dev.whyoleg.cryptography.serialization.asn1.*
109
import kotlinx.serialization.*
1110
import kotlin.jvm.*
1211

12+
// Certificate ::= SEQUENCE {
13+
// tbsCertificate TBSCertificate,
14+
// signatureAlgorithm AlgorithmIdentifier,
15+
// signatureValue BIT STRING }
16+
//
17+
// TBSCertificate ::= SEQUENCE {
18+
// version [0] EXPLICIT Version DEFAULT v1,
19+
// serialNumber CertificateSerialNumber,
20+
// signature AlgorithmIdentifier,
21+
// issuer Name,
22+
// validity Validity,
23+
// subject Name,
24+
// subjectPublicKeyInfo SubjectPublicKeyInfo,
25+
// issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
26+
// -- If present, version MUST be v2 or v3
27+
// subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
28+
// -- If present, version MUST be v2 or v3
29+
// extensions [3] EXPLICIT Extensions OPTIONAL
30+
// -- If present, version MUST be v3
31+
// }
32+
//
33+
// Version ::= INTEGER { v1(0), v2(1), v3(2) }
34+
//
35+
// CertificateSerialNumber ::= INTEGER
36+
//
37+
// Validity ::= SEQUENCE {
38+
// notBefore Time,
39+
// notAfter Time }
40+
//
41+
// Time ::= CHOICE {
42+
// utcTime UTCTime,
43+
// generalTime GeneralizedTime }
44+
//
45+
// UniqueIdentifier ::= BIT STRING
46+
//
47+
// SubjectPublicKeyInfo ::= SEQUENCE {
48+
// algorithm AlgorithmIdentifier,
49+
// subjectPublicKey BIT STRING }
50+
//
51+
// Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
52+
//
53+
// Extension ::= SEQUENCE {
54+
// extnID OBJECT IDENTIFIER,
55+
// critical BOOLEAN DEFAULT FALSE,
56+
// extnValue OCTET STRING
57+
// -- contains the DER encoding of an ASN.1 value
58+
// -- corresponding to the extension type identified
59+
// -- by extnID
60+
// }
61+
62+
63+
// Instant -> GeneralizedTime | UTCTime | DATE
64+
65+
66+
//private sealed class TimeX {
67+
// value class utc(@Asn1UTCTime val time: Instant) : TimeX()
68+
// value class general(@Asn1GeneralizedTime val time: Instant) : TimeX()
69+
//}
70+
1371
//Certificate ::= SEQUENCE {
1472
// tbsCertificate TBSCertificate,
1573
// signatureAlgorithm AlgorithmIdentifier,
1674
// signatureValue BIT STRING }
1775
@Serializable
18-
public class Certificate(
76+
public data class Certificate(
1977
public val tbsCertificate: TbsCertificate,
2078
public val signatureAlgorithm: AlgorithmIdentifier,
21-
public val signatureValue: BitString,
79+
public val signatureValue: BitArray,
2280
)
2381

2482
// TBSCertificate ::= SEQUENCE {
@@ -38,40 +96,44 @@ public class Certificate(
3896
// }
3997
//
4098
@Serializable
41-
public class TbsCertificate(
99+
public data class TbsCertificate(
100+
@ContextSpecificTag(0, ContextSpecificTag.TagType.EXPLICIT)
42101
public val version: Int = 0, // TODO EXPLICIT?
43102
public val serialNumber: CertificateSerialNumber,
44103
public val signature: AlgorithmIdentifier,
45104
public val issuer: Name,
46105
public val validity: Validity,
47106
public val subject: Name,
48107
public val subjectPublicKeyInfo: SubjectPublicKeyInfo,
108+
@ContextSpecificTag(1, ContextSpecificTag.TagType.IMPLICIT)
49109
public val issuerUniqueID: UniqueIdentifier? = null,
110+
@ContextSpecificTag(2, ContextSpecificTag.TagType.IMPLICIT)
50111
public val subjectUniqueID: UniqueIdentifier? = null,
112+
@ContextSpecificTag(3, ContextSpecificTag.TagType.EXPLICIT)
51113
public val extensions: Extensions? = null,
52114
)
53115

54116
public typealias CertificateSerialNumber = BigInt
55117

56118
@Serializable
57-
public class Validity(
119+
public data class Validity(
58120
public val notBefore: Time,
59121
public val notAfter: Time,
60122
)
61123

62124
// TODO!!!
63125
@Serializable
64-
public class Time(
126+
public data class Time(
65127
public val utcTime: String? = null,
66128
public val generalTime: String? = null,
67129
)
68130

69-
public typealias UniqueIdentifier = BitString
131+
public typealias UniqueIdentifier = BitArray
70132

71133
public typealias Extensions = List<Extension>
72134

73135
@Serializable
74-
public class Extension(
136+
public data class Extension(
75137
public val extnID: ObjectIdentifier,
76138
public val critical: Boolean = false,
77139
public val extnValue: ByteArray,
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* Copyright (c) 2025 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package dev.whyoleg.cryptography.serialization.asn1.modules
6+
7+
import dev.whyoleg.cryptography.serialization.asn1.*
8+
import kotlinx.serialization.*
9+
import kotlin.io.encoding.*
10+
import kotlin.test.*
11+
12+
class Rfc5280SamplesTest {
13+
// https://datatracker.ietf.org/doc/html/rfc5280#appendix-C.2
14+
private val cert2 = """
15+
MIICcTCCAdqgAwIBAgIBEjANBgkqhkiG9w0BAQUFADBDMRMwEQYKCZImiZPyLGQB
16+
GRYDY29tMRcwFQYKCZImiZPyLGQBGRYHZXhhbXBsZTETMBEGA1UEAxMKRXhhbXBs
17+
ZSBDQTAeFw0wNDA5MTUxMTQ4MjFaFw0wNTAzMTUxMTQ4MjFaMEMxEzARBgoJkiaJ
18+
k/IsZAEZFgNjb20xFzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMRMwEQYDVQQDEwpF
19+
bmQgRW50aXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDhauQDMJcCPPQQ
20+
87UeTX8Ue/b10HjppIrwo3Xs7bZWln+ImYWa8j5od4frntGfwLQX3KuJI6QdfhYj
21+
TE+oTfUxuHyq4xpJCfRLJtsnZzCCEgFK6Rq2wQxTi2z8L3pD7DM2fjKye9WqzwEU
22+
xhLsE/ItFHqLIVgUE0xGo5ryFpX/IwIDAQABo3UwczAhBgNVHREEGjAYgRZlbmQu
23+
ZW50aXR5QGV4YW1wbGUuY29tMB0GA1UdDgQWBBQXe5Iw/0TWZuGQECJsFk/AjkHd
24+
bTAfBgNVHSMEGDAWgBQIaK+FM8g5Snr4gpOOcGpKIIQsMjAOBgNVHQ8BAf8EBAMC
25+
BsAwDQYJKoZIhvcNAQEFBQADgYEAACAoNFtoMgG7CjYOrXHFlRrhBM+urcdiFKQb
26+
NjHA4gw92R7AANwQoLqFb0HLYnq3TGOBJl7SgEVeM+dwRTs5OyZKnDvyJjZpCHm7
27+
+5ZDd0thi6GrkWTg8zdhPBqjpMmKsr9z1E3kWORi6rwgdJKGDs6EYHbpc7vHhdOR
28+
RepiXc0=
29+
""".trimIndent()
30+
31+
// https://datatracker.ietf.org/doc/html/rfc5280#appendix-C.3
32+
private val cert3 = """
33+
MIIDjjCCA06gAwIBAgICAQAwCQYHKoZIzjgEAzBHMRMwEQYKCZImiZPyLGQBGRYD
34+
Y29tMRcwFQYKCZImiZPyLGQBGRYHZXhhbXBsZTEXMBUGA1UEAxMORXhhbXBsZSBE
35+
U0EgQ0EwHhcNMDQwNTAyMTY0NzM4WhcNMDUwNTAyMTY0NzM4WjBHMRMwEQYKCZIm
36+
iZPyLGQBGRYDY29tMRcwFQYKCZImiZPyLGQBGRYHZXhhbXBsZTEXMBUGA1UEAxMO
37+
RFNBIEVuZCBFbnRpdHkwggG3MIIBLAYHKoZIzjgEATCCAR8CgYEAtosPlCuazqUl
38+
xvLt/PuVMqwBEjO54BytkJu8SFSe85R3PCxxNVXm/k8iy9XYPomTM038vU9BZD6i
39+
mHDsMbRQ3uvxmCgKyT5Es/0il5aD0Bij4701W//uoyFyanuW2rk/HlqQryTWIPAN
40+
IafUArka/Kwh+56UnktCRZ5qskhj/kMCFQCyDbCxAd8MZiT8E5K6Vfd9V3SB5QKB
41+
gQCav0ax9T9EPcmlZfuRwI5H8QrDAUfCREI2qZKB3lfF4GiGWAB7H/mbd6HFEKWA
42+
kXhRUTz2/PzMRsaBeJKEPfSTPQw4fhpbmU6rFGT2DCEiTigInJK5Zp9A6JX21TEq
43+
7zmiYseybZ5YxDqoEYGEba/4tBm0whGu0CI7qiB/7h5XGAOBhAACgYAwtnX3fCAx
44+
rji7fg0rq6CcS98g1SQTPM2Y5V9st8G6SrqplYBT8A1y3DM39AEL9QQfnS4fYtiE
45+
OpslCVotyEaOK9T1DTvHLcZsuZjBJTpETo7KlWE1fM4VMVwjEx6iBdF6JBzL03IJ
46+
kP+bnSjAoQrsRp8NuNDc0BimK175j7WVvqOByjCBxzA5BgNVHREEMjAwhi5odHRw
47+
Oi8vd3d3LmV4YW1wbGUuY29tL3VzZXJzL0RTQWVuZGVudGl0eS5odG1sMCEGA1Ud
48+
EgQaMBiGFmh0dHA6Ly93d3cuZXhhbXBsZS5jb20wHQYDVR0OBBYEFN0lZpZDq3gR
49+
Q0T+lRb52ba3AmaNMB8GA1UdIwQYMBaAFIbKpSKBYu+tCom8rXJBLClJ9IZWMBcG
50+
A1UdIAQQMA4wDAYKYIZIAWUDAgEwCTAOBgNVHQ8BAf8EBAMCB4AwCQYHKoZIzjgE
51+
AwMvADAsAhRlVwc03dzKzF70AvRWQixe4bM7gAIUYPQxF8r0z//u9Ain2bJhvrHD
52+
2r8=
53+
""".trimIndent()
54+
55+
// https://datatracker.ietf.org/doc/html/rfc5280#appendix-C.4
56+
private val crl = """
57+
MIIBYDCBygIBATANBgkqhkiG9w0BAQUFADBDMRMwEQYKCZImiZPyLGQBGRYDY29t
58+
MRcwFQYKCZImiZPyLGQBGRYHZXhhbXBsZTETMBEGA1UEAxMKRXhhbXBsZSBDQRcN
59+
MDUwMjA1MTIwMDAwWhcNMDUwMjA2MTIwMDAwWjAiMCACARIXDTA0MTExOTE1NTcw
60+
M1owDDAKBgNVHRUEAwoBAaAvMC0wHwYDVR0jBBgwFoAUCGivhTPIOUp6+IKTjnBq
61+
SiCELDIwCgYDVR0UBAMCAQwwDQYJKoZIhvcNAQEFBQADgYEAItwYffcIzsx10NBq
62+
m60Q9HYjtIFutW2+DvsVFGzIF20f7pAXom9g5L2qjFXejoRvkvifEBInr0rUL4Xi
63+
NkR9qqNMJTgV/wD9Pn7uPSYS69jnK2LiK8NGgO94gtEVxtCccmrLznrtZ5mLbnCB
64+
fUNCdMGmr8FVF6IzTNYGmCuk/C4=
65+
""".trimIndent()
66+
67+
/**
68+
* RSA Self-Signed Certificate (https://datatracker.ietf.org/doc/html/rfc5280#appendix-C.1)
69+
* This appendix contains an annotated hex dump of a 578 byte version 3 certificate.
70+
* The certificate contains the following information:
71+
* - (a) the serial number is 17;
72+
* - (b) the certificate is signed with RSA and the SHA-1 hash algorithm;
73+
* - (c) the issuer's distinguished name is cn=Example CA,dc=example,dc=com;
74+
* - (d) the subject's distinguished name is cn=Example CA,dc=example,dc=com;
75+
* - (e) the certificate was issued on April 30, 2004 and expired on April 30, 2005;
76+
* - (f) the certificate contains a 1024-bit RSA public key;
77+
* - (g) the certificate contains a subject key identifier extension generated using method (1) of Section 4.2.1.2; and
78+
* - (h) the certificate is a CA certificate (as indicated through the basic constraints extension).
79+
*/
80+
@Test
81+
fun test1() {
82+
val base64EncodedCertificate = """
83+
MIICPjCCAaegAwIBAgIBETANBgkqhkiG9w0BAQUFADBDMRMwEQYKCZImiZPyLGQB
84+
GRYDY29tMRcwFQYKCZImiZPyLGQBGRYHZXhhbXBsZTETMBEGA1UEAxMKRXhhbXBs
85+
ZSBDQTAeFw0wNDA0MzAxNDI1MzRaFw0wNTA0MzAxNDI1MzRaMEMxEzARBgoJkiaJ
86+
k/IsZAEZFgNjb20xFzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMRMwEQYDVQQDEwpF
87+
eGFtcGxlIENBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDC15dtKHCqW88j
88+
LoBwOe7bb9Ut1WpPejQt+SJyR3Ad74DpyjCMAMSabltFtG6l5myUDfqR6UD8JZ3H
89+
t2gZVo8RcGrX8ckRTzp+P5mNbnaldF9epFVT5cdoNlPHHTsSpoX+vW6hyt81UKwI
90+
17m0flz+4qMs0SOEqpjAm2YYmmhH6QIDAQABo0IwQDAdBgNVHQ4EFgQUCGivhTPI
91+
OUp6+IKTjnBqSiCELDIwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w
92+
DQYJKoZIhvcNAQEFBQADgYEAbPgCdKZh4mQEplQMbHITrTxH+/ZlE6mFkDPqdqMm
93+
2fzRDhVfKLfvk7888+I+fLlS/BZuKarh9Hpv1X/vs5XK82aIg06hNUWEy7ybuMit
94+
xV5G2QsOjYDhMyvcviuSfkpDqWrvimNhs25HOL7oDaNnXfP6kYE8krvFXyUl63zn
95+
2KE=
96+
""".trimIndent()
97+
val certificate = Der.decodeFromByteArray<Certificate>(Base64.Pem.decode(base64EncodedCertificate))
98+
99+
println(certificate)
100+
}
101+
}

0 commit comments

Comments
 (0)