@@ -46,6 +46,7 @@ type sessionRecord struct {
46
46
47
47
type chain struct {
48
48
isValid bool
49
+ isSS bool
49
50
s string
50
51
}
51
52
@@ -77,38 +78,72 @@ func main() {
77
78
}
78
79
79
80
} else {
80
- jsonPath = "./test.json"
81
-
82
- // read corresponding json file
83
- dat , err := ioutil .ReadFile ( jsonPath )
81
+ var path [] string
82
+ path = append ( path , "./sessions" )
83
+ path = append ( path , "" )
84
+ files , err := ioutil .ReadDir ( path [ 0 ] )
84
85
if err != nil {
85
86
log .Fatal (err )
86
87
}
87
- // Unmarshal JSON file
88
- s := sessionRecord {}
89
- _ = json .Unmarshal ([]byte (dat ), & s )
90
88
91
- // Insert Session
92
- ids , err := insertSession (& s )
93
- if err != nil {
94
- log .Fatal (fmt .Sprintf ("Insert Sessions into DB failed: %q" , err ))
95
- }
96
- // Attempt to roughly build a chain of trust
97
- session := buildChain (& s )
89
+ for _ , f := range files {
98
90
99
- // Insert Certificates
100
- idc , err := insertCertificates (session )
101
- if err != nil {
102
- log .Fatal (fmt .Sprintf ("Insert Certificate into DB failed: %q" , err ))
103
- }
104
- // Create the relationship between certificates and sessions
105
- err = linkSessionCerts (ids , idc )
106
- if err != nil {
107
- log .Fatal (fmt .Sprintf ("Could not link Certs and Session into DB: %q" , err ))
91
+ path [1 ] = f .Name ()
92
+ jsonPath = strings .Join (path , "/" )
93
+
94
+ // read corresponding json file
95
+ dat , err := ioutil .ReadFile (jsonPath )
96
+ if err != nil {
97
+ log .Fatal (err )
98
+ }
99
+ // Unmarshal JSON file
100
+ s := sessionRecord {}
101
+ _ = json .Unmarshal ([]byte (dat ), & s )
102
+
103
+ if len (s .Certificates ) > 0 {
104
+ // Insert Session
105
+ ids , err := insertSession (& s )
106
+ if err != nil {
107
+ log .Fatal (fmt .Sprintf ("Insert Sessions into DB failed: %q" , err ))
108
+ }
109
+ // Attempt to roughly build a chain of trust
110
+ session := buildChain (& s )
111
+
112
+ // Insert Certificates
113
+ idc , err := insertCertificates (session )
114
+ if err != nil {
115
+ log .Fatal (fmt .Sprintf ("Insert Certificate into DB failed: %q" , err ))
116
+ }
117
+ // Create the relationship between certificates and sessions
118
+ err = linkSessionCerts (ids , idc )
119
+ if err != nil {
120
+ log .Fatal (fmt .Sprintf ("Could not link Certs and Session into DB: %q" , err ))
121
+ }
122
+
123
+ // Create ja3* records
124
+ err = insertJA3 (session )
125
+ if err != nil {
126
+ log .Fatal (fmt .Sprintf ("Could not insert JA3 into DB: %q" , err ))
127
+ }
128
+ }
108
129
}
109
130
}
110
131
}
111
132
133
+ func insertJA3 (s * sessionRecord ) error {
134
+ q := `INSERT INTO "ja3" (hash, raw, type) VALUES ($1, $2, $3) ON CONFLICT DO NOTHING`
135
+ _ , err := db .Exec (q , s .JA3Digest , s .JA3 , "ja3" )
136
+ if err != nil {
137
+ return err
138
+ }
139
+ q = `INSERT INTO "ja3" (hash, raw, type) VALUES ($1, $2, $3) ON CONFLICT DO NOTHING`
140
+ _ , err = db .Exec (q , s .JA3SDigest , s .JA3S , "ja3s" )
141
+ if err != nil {
142
+ return err
143
+ }
144
+ return nil
145
+ }
146
+
112
147
// insertPublicKeys insert each public key of each certificate of a session
113
148
func insertPublicKey (c x509.Certificate ) (string , error ) {
114
149
pub , err := x509 .ParsePKIXPublicKey (c .RawSubjectPublicKeyInfo )
@@ -119,22 +154,22 @@ func insertPublicKey(c x509.Certificate) (string, error) {
119
154
120
155
switch pub := pub .(type ) {
121
156
case * rsa.PublicKey :
122
- q := `INSERT INTO "public_key" (hash, type, modulus, exponent, modulus_size) VALUES ($1, $2, $3, $4, $5)`
123
- _ , err := db .Query (q , hash , "RSA" , (* BigNumber )(pub .N ), pub .E , pub .Size ())
157
+ q := `INSERT INTO "public_key" (hash, type, modulus, exponent, modulus_size) VALUES ($1, $2, $3, $4, $5) ON CONFLICT DO NOTHING `
158
+ _ , err := db .Exec (q , hash , "RSA" , (* BigNumber )(pub .N ), pub .E , pub .Size ())
124
159
if err != nil {
125
- return hash , nil
160
+ return hash , err
126
161
}
127
162
case * dsa.PublicKey :
128
- q := `INSERT INTO "public_key" (hash, type, "G", "P", "Q", "Y") VALUES ($1, $2, $3, $4, $5, $6)`
129
- _ , err := db .Query (q , hash , "DSA" , (* BigNumber )(pub .Parameters .G ), (* BigNumber )(pub .Parameters .P ), (* BigNumber )(pub .Parameters .Q ), (* BigNumber )(pub .Y ))
163
+ q := `INSERT INTO "public_key" (hash, type, "G", "P", "Q", "Y") VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT DO NOTHING `
164
+ _ , err := db .Exec (q , hash , "DSA" , (* BigNumber )(pub .Parameters .G ), (* BigNumber )(pub .Parameters .P ), (* BigNumber )(pub .Parameters .Q ), (* BigNumber )(pub .Y ))
130
165
if err != nil {
131
- return hash , nil
166
+ return hash , err
132
167
}
133
168
case * ecdsa.PublicKey :
134
- q := `INSERT INTO "public_key" (hash, type, "Y", "X", "P", "N", "B", "bitsize", "Gx", "Gy") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) `
135
- _ , err := db .Query (q , hash , "ECDSA" , pub .Y , pub .X , pub .Curve .Params ().P , pub .Curve .Params ().N , pub .Curve .Params ().B , pub .Curve .Params ().BitSize , pub .Curve .Params ().Gx , pub .Curve .Params ().Gy )
169
+ q := `INSERT INTO "public_key" (hash, type, "Y", "X", "P", "N", "B", "bitsize", "Gx", "Gy", "curve_name" ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) ON CONFLICT DO NOTHING `
170
+ _ , err := db .Exec (q , hash , "ECDSA" , ( * BigNumber )( pub .Y ), ( * BigNumber )( pub .X ), ( * BigNumber )( pub .Curve .Params ().P ), ( * BigNumber )( pub .Curve .Params ().N ), ( * BigNumber )( pub .Curve .Params ().B ) , pub .Curve .Params ().BitSize , ( * BigNumber )( pub .Curve .Params ().Gx ), ( * BigNumber )( pub .Curve .Params ().Gy ), pub . Params (). Name )
136
171
if err != nil {
137
- return hash , nil
172
+ return hash , err
138
173
}
139
174
default :
140
175
return hash , fmt .Errorf ("PKIx: could not determine the type of key %g" , pub )
@@ -149,8 +184,8 @@ func (bn *BigNumber) Value() (driver.Value, error) {
149
184
// linkSessionCerts creates the link between a session and its certificates
150
185
func linkSessionCerts (ids int64 , idc []string ) error {
151
186
for _ , i := range idc {
152
- q := `INSERT INTO "many_sessionRecord_has_many_certificate" ("id_sessionRecord", "hash_certificate") VALUES ($1, $2)`
153
- _ , err := db .Query (q , ids , i )
187
+ q := `INSERT INTO "many_sessionRecord_has_many_certificate" ("id_sessionRecord", "hash_certificate") VALUES ($1, $2) ON CONFLICT DO NOTHING `
188
+ _ , err := db .Exec (q , ids , i )
154
189
if err != nil {
155
190
return err
156
191
}
@@ -164,57 +199,107 @@ func linkSessionCerts(ids int64, idc []string) error {
164
199
// does not touch the original slice and mark the chain as invalid.
165
200
func buildChain (s * sessionRecord ) * sessionRecord {
166
201
certChain := make ([]certMapElm , 0 )
202
+ // First find if there are any duplicates certificate
203
+ dedup := unique (s .Certificates )
204
+ deduplen := len (dedup )
205
+
206
+ if deduplen > 1 {
207
+ // Then we find the leaf
208
+ removed := 0
209
+ for i , c := range dedup {
210
+ if ! c .Certificate .IsCA {
211
+ certChain = append (certChain , c )
212
+ // Remove this element from the list
213
+ dedup = append (dedup [:i - removed ], dedup [i + 1 - removed :]... )
214
+ removed ++
215
+ }
216
+ }
167
217
168
- // First we find the leaf
169
- for _ , c := range s .Certificates {
170
- fmt .Println (c .Certificate .Issuer .String ())
171
- fmt .Println (c .Certificate .Subject .String ())
172
- fmt .Println (c .Certificate .Subject .String () == c .Certificate .Issuer .String ())
173
- if ! c .Certificate .IsCA {
174
- certChain = append (certChain , c )
218
+ cursor := len (certChain )
219
+ // Find the parent of each certificate
220
+ for i := 0 ; i < cursor ; i ++ {
221
+ p , success , isSS := findParent (dedup , certChain [i ])
222
+ // if we found a root, no need to go any further
223
+ if isSS {
224
+ p .chain .isSS = true
225
+ certChain = append (certChain , p )
226
+ break
227
+ }
228
+ if success {
229
+ p .chain .isSS = false
230
+ certChain = append (certChain , p )
231
+ }
232
+ cursor = len (certChain )
175
233
}
176
- }
177
- // Find the parent of each certificate
178
- for _ , _ = range s .Certificates {
179
- for i , _ := range s .Certificates {
180
- if s .Certificates [i ].Certificate .Subject .String () == certChain [len (certChain )- 1 ].Issuer .String () {
181
- certChain = append (certChain , s .Certificates [i ])
234
+
235
+ // Write the new chain if it's valid
236
+ if len (certChain ) >= deduplen - 1 {
237
+ cstr := make ([]string , 0 )
238
+ for i := len (certChain ) - 1 ; i >= 0 ; i -- {
239
+ certChain [i ].chain .isValid = true
240
+ if ! certChain [i ].chain .isSS {
241
+ cstr = append (cstr , certChain [i ].CertHash )
242
+ certChain [i ].chain .s = strings .Join (cstr , "." )
243
+ }
182
244
}
245
+ tmp := s
246
+ tmp .Certificates = certChain
247
+ return tmp
183
248
}
249
+ // Only one cert in the chain
250
+ } else {
251
+ s .Certificates [0 ].chain = chain {true , s .Certificates [0 ].Certificate .Issuer .String () == s .Certificates [0 ].Certificate .Subject .String (), s .Certificates [0 ].CertHash }
184
252
}
185
- // Write the new chain
186
- if len (certChain ) == len (s .Certificates ) {
187
- cstr := make ([]string , 0 )
188
- for i := len (certChain ) - 1 ; i >= 0 ; i -- {
189
- certChain [i ].chain .isValid = true
190
- cstr = append (cstr , certChain [i ].CertHash )
191
- certChain [i ].chain .s = strings .Join (cstr , "." )
253
+
254
+ return s
255
+ }
256
+
257
+ func findParent (dedup []certMapElm , c certMapElm ) (certMapElm , bool , bool ) {
258
+ // A Root or SSC signs itself
259
+ if c .Certificate .Subject .String () == c .Certificate .Issuer .String () {
260
+ return c , true , true
261
+ }
262
+
263
+ // A leaf or a node has a parent
264
+ for _ , candidate := range dedup {
265
+ if candidate .Certificate .Subject .String () == c .Certificate .Issuer .String () {
266
+ return candidate , true , false
192
267
}
193
- tmp := s
194
- tmp .Certificates = certChain
195
- return tmp
196
268
}
197
- return s
269
+
270
+ return c , false , false
271
+ }
272
+
273
+ func unique (s []certMapElm ) []certMapElm {
274
+ keys := make (map [string ]bool )
275
+ var list []certMapElm
276
+ for _ , entry := range s {
277
+ if _ , value := keys [entry .CertHash ]; ! value {
278
+ keys [entry .CertHash ] = true
279
+ list = append (list , entry )
280
+ }
281
+ }
282
+ return list
198
283
}
199
284
200
285
func insertCertificate (c certMapElm ) (string , error ) {
201
- q := `INSERT INTO "certificate" (hash, "is_CA", issuer, subject, cert_chain, is_valid_chain, file_path) VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING hash`
202
- var hash string
203
- err := db .QueryRow (q , c .CertHash , c .Certificate .IsCA , c .Certificate .Issuer .String (), c .Certificate .Subject .String (), c .chain .s , c .chain .isValid , getFullPath (c .CertHash )).Scan (& hash )
286
+ q := `INSERT INTO "certificate" (hash, "is_CA", "is_SS", issuer, subject, cert_chain, is_valid_chain, file_path) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) ON CONFLICT DO NOTHING`
287
+ _ , err := db .Exec (q , c .CertHash , c .Certificate .IsCA , c .chain .isSS , c .Certificate .Issuer .String (), c .Certificate .Subject .String (), c .chain .s , c .chain .isValid , getFullPath (c .CertHash ))
204
288
if err != nil {
205
- return hash , err
289
+ return c . CertHash , err
206
290
}
207
291
key , err := insertPublicKey (* c .Certificate )
208
292
if err != nil {
209
- return hash , err
293
+ return c . CertHash , err
210
294
}
211
-
212
- q = `INSERT INTO "many_certificate_has_many_public_key" ("hash_certificate", "hash_public_key") VALUES ($1, $2)`
213
- _ , err = db .Query (q , hash , key )
295
+ fmt .Println (c .CertHash )
296
+ fmt .Println (key )
297
+ q = `INSERT INTO "many_certificate_has_many_public_key" ("hash_certificate", "hash_public_key") VALUES ($1, $2) ON CONFLICT DO NOTHING `
298
+ _ , err = db .Exec (q , c .CertHash , key )
214
299
if err != nil {
215
- return hash , err
300
+ return c . CertHash , err
216
301
}
217
- return hash , nil
302
+ return c . CertHash , nil
218
303
}
219
304
220
305
// getFullPath takes a certificate's hash and return the full path to
0 commit comments