Skip to content

Commit d8fa301

Browse files
snwoodslindig
authored andcommitted
CP-50193: Update new fingerprint fields on DB upgrade
The new fingerprint_sha256 and fingerprint_sha1 fields will be empty when upgrading from a version without the fields. This commit checks for this and fills them in, stopping the certificate from being needlessly reinstalled. Signed-off-by: Steven Woods <steven.woods@citrix.com>
1 parent 3c41333 commit d8fa301

File tree

7 files changed

+47
-22
lines changed

7 files changed

+47
-22
lines changed

ocaml/idl/datamodel_certificate.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,10 @@ let t =
6969
[(Published, rel_stockholm, ""); (Deprecated, "24.19.0", "")]
7070
~ty:String "fingerprint" ~default_value:(Some (VString ""))
7171
"Use fingerprint_sha256 instead"
72-
; field ~qualifier:StaticRO ~lifecycle ~ty:String "fingerprint_sha256"
72+
; field ~qualifier:StaticRO ~lifecycle:[] ~ty:String "fingerprint_sha256"
7373
~default_value:(Some (VString ""))
7474
"The certificate's SHA256 fingerprint / hash"
75-
; field ~qualifier:StaticRO ~lifecycle ~ty:String "fingerprint_sha1"
75+
; field ~qualifier:StaticRO ~lifecycle:[] ~ty:String "fingerprint_sha1"
7676
~default_value:(Some (VString ""))
7777
"The certificate's SHA1 fingerprint / hash"
7878
]

ocaml/idl/datamodel_common.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ open Datamodel_roles
1010
to leave a gap for potential hotfixes needing to increment the schema version.*)
1111
let schema_major_vsn = 5
1212

13-
let schema_minor_vsn = 779
13+
let schema_minor_vsn = 780
1414

1515
(* Historical schema versions just in case this is useful later *)
1616
let rio_schema_major_vsn = 5

ocaml/idl/datamodel_lifecycle.ml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ let prototyped_of_field = function
2727
Some "23.14.0"
2828
| "Repository", "gpgkey_path" ->
2929
Some "22.12.0"
30+
| "Certificate", "fingerprint_sha1" ->
31+
Some "24.19.1-next"
32+
| "Certificate", "fingerprint_sha256" ->
33+
Some "24.19.1-next"
3034
| "Cluster_host", "last_update_live" ->
3135
Some "24.3.0"
3236
| "Cluster_host", "live" ->

ocaml/idl/schematest.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ let hash x = Digest.string x |> Digest.to_hex
33
(* BEWARE: if this changes, check that schema has been bumped accordingly in
44
ocaml/idl/datamodel_common.ml, usually schema_minor_vsn *)
55

6-
let last_known_schema_hash = "efdb1c7e536362523741ccdb7f33f797"
6+
let last_known_schema_hash = "7885f7b085e4a5e32977a4b222030412"
77

88
let current_schema_hash : string =
99
let open Datamodel_types in

ocaml/xapi/certificates.ml

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ let pp_hash hash =
8080
in
8181
String.init length value_of
8282

83+
let pp_fingerprint ~hash_type cert =
84+
X509.Certificate.fingerprint hash_type cert |> pp_hash
85+
8386
let safe_char c =
8487
match c with
8588
| 'A' .. 'Z' | 'a' .. 'z' | '0' .. '9' | '.' | '_' | '-' ->
@@ -218,12 +221,8 @@ end = struct
218221
let not_before, not_after =
219222
dates_of_ptimes (X509.Certificate.validity certificate)
220223
in
221-
let fingerprint_sha256 =
222-
X509.Certificate.fingerprint `SHA256 certificate |> pp_hash
223-
in
224-
let fingerprint_sha1 =
225-
X509.Certificate.fingerprint `SHA1 certificate |> pp_hash
226-
in
224+
let fingerprint_sha256 = pp_fingerprint ~hash_type:`SHA256 certificate in
225+
let fingerprint_sha1 = pp_fingerprint ~hash_type:`SHA1 certificate in
227226
let uuid = Uuidx.(to_string (make ())) in
228227
let ref' = Ref.make () in
229228
Db.Certificate.create ~__context ~ref:ref' ~uuid ~host ~not_before

ocaml/xapi/certificates.mli

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ val pem_of_string : string -> X509.Certificate.t
2020

2121
val pp_hash : Cstruct.t -> string
2222

23+
val pp_fingerprint :
24+
hash_type:Mirage_crypto.Hash.hash -> X509.Certificate.t -> string
25+
2326
val validate_name : t_trusted -> string -> unit
2427

2528
val hostnames_of_pem_cert :

ocaml/xapi/certificates_sync.ml

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,26 @@ let install ~__context ~host:_ ~type' cert =
2929
error "certificates_sync.install exception: %s" (Printexc.to_string e) ;
3030
Error (`Msg ("installation of host certificate failed", []))
3131

32+
type to_update = Certificate | Hashes of {sha256: string; sha1: string}
33+
3234
(** determine if the database is up to date by comparing the fingerprint
3335
of xapi-ssl.pem with the entry in the database *)
34-
let is_unchanged ~__context cert_ref cert =
36+
let to_update ~__context cert_ref cert =
3537
let ref_hash =
3638
Db.Certificate.get_fingerprint_sha256 ~__context ~self:cert_ref
3739
in
38-
let cert_hash =
39-
X509.Certificate.fingerprint `SHA256 cert |> Certificates.pp_hash
40-
in
41-
cert_hash = ref_hash
40+
let sha256 = Certificates.pp_fingerprint ~hash_type:`SHA256 cert in
41+
if ref_hash = "" then
42+
(* We must be upgrading from a version predating fingerprint_sha256, so check fingerprint instead *)
43+
if sha256 = Db.Certificate.get_fingerprint ~__context ~self:cert_ref then
44+
let sha1 = Certificates.pp_fingerprint ~hash_type:`SHA1 cert in
45+
Some (Hashes {sha256; sha1})
46+
else
47+
Some Certificate
48+
else if sha256 = ref_hash then
49+
None
50+
else
51+
Some Certificate
4252

4353
(** [get_server_cert] loads [path] from the file system and
4454
returns it decoded *)
@@ -76,17 +86,26 @@ let sync ~__context ~type' =
7686
| [] ->
7787
info "Host %s has no active server certificate" host_uuid ;
7888
install ~__context ~host ~type' cert
79-
| [cert_ref] ->
80-
let unchanged = is_unchanged ~__context cert_ref cert in
81-
if unchanged then (
82-
info "Active server certificate for host %s is unchanged" host_uuid ;
83-
Ok ()
84-
) else (
89+
| [cert_ref] -> (
90+
match to_update ~__context cert_ref cert with
91+
| Some Certificate ->
8592
info "Server certificate for host %s changed - updating" host_uuid ;
8693
let* () = install ~__context ~host ~type' cert in
8794
uninstall ~__context cert_ref ;
8895
Ok ()
89-
)
96+
| Some (Hashes {sha256; sha1}) ->
97+
info "Active server certificate for host %s is unchanged" host_uuid ;
98+
Db.Certificate.set_fingerprint_sha256 ~__context ~self:cert_ref
99+
~value:sha256 ;
100+
Db.Certificate.set_fingerprint_sha1 ~__context ~self:cert_ref
101+
~value:sha1 ;
102+
info "Populated new fingerprint fields: sha256= %s; sha1= %s" sha256
103+
sha1 ;
104+
Ok ()
105+
| None ->
106+
info "Active server certificate for host %s is unchanged" host_uuid ;
107+
Ok ()
108+
)
90109
| cert_refs ->
91110
warn "The host has more than one certificate: %s"
92111
(String.concat ", " (List.map Ref.string_of cert_refs)) ;

0 commit comments

Comments
 (0)