@@ -7,6 +7,10 @@ defmodule NervesKey do
77  alias  NervesKey . { Config ,  OTP ,  Data ,  ProvisioningInfo } 
88
99  @ build_year  DateTime . utc_now ( ) . year 
10+   @ settings_slots  [ 8 ,  7 ,  6 ,  5 ] 
11+   @ settings_max_length  Enum . reduce ( @ settings_slots ,  0 ,  fn  slot ,  acc  -> 
12+                          acc  +  ATECC508A.DataZone . slot_size ( slot ) 
13+                        end ) 
1014
1115  @ typedoc  "Which device/signer certificate pair to use" 
1216  @ type  certificate_pair ( )  ::  :primary  |  :aux 
@@ -230,6 +234,91 @@ defmodule NervesKey do
230234    % ProvisioningInfo { manufacturer_sn:  Base . encode32 ( sn ,  padding:  false ) ,  board_name:  "NervesKey" } 
231235  end 
232236
237+   @ doc  """ 
238+   Return the settings block as a binary 
239+   """ 
240+   @ spec  get_raw_settings ( ATECC508A.Transport . t ( ) )  ::  { :ok ,  binary ( ) }  |  { :error ,  atom ( ) } 
241+   def  get_raw_settings ( transport )  do 
242+     all_reads  =  Enum . map ( @ settings_slots ,  & ATECC508A.DataZone . read ( transport ,  & 1 ) ) 
243+ 
244+     case  Enum . find ( all_reads ,  fn  { result ,  _ }  ->  result  !=  :ok  end )  do 
245+       nil  -> 
246+         raw  =  Enum . map_join ( all_reads ,  fn  { :ok ,  contents }  ->  contents  end ) 
247+         { :ok ,  raw } 
248+ 
249+       error  -> 
250+         error 
251+     end 
252+   end 
253+ 
254+   @ doc  """ 
255+   Return all of the setting stored in the NervesKey as a map 
256+   """ 
257+   @ spec  get_settings ( ATECC508A.Transport . t ( ) )  ::  { :ok ,  map ( ) }  |  { :error ,  atom ( ) } 
258+   def  get_settings ( transport )  do 
259+     with  { :ok ,  raw_settings }  <-  get_raw_settings ( transport )  do 
260+       try  do 
261+         settings  =  :erlang . binary_to_term ( raw_settings ,  [ :safe ] ) 
262+         { :ok ,  settings } 
263+       catch 
264+         _ ,  _  ->  { :error ,  :corrupt } 
265+       end 
266+     end 
267+   end 
268+ 
269+   @ doc  """ 
270+   Store settings on the NervesKey 
271+ 
272+   This overwrites all of the settings that are currently on the key and should 
273+   be used with care since there's no protection against a race condition with 
274+   other NervesKey users. 
275+   """ 
276+   @ spec  put_settings ( ATECC508A.Transport . t ( ) ,  map ( ) )  ::  :ok 
277+   def  put_settings ( transport ,  settings )  when  is_map ( settings )  do 
278+     raw_settings  =  :erlang . term_to_binary ( settings ) 
279+     put_raw_settings ( transport ,  raw_settings ) 
280+   end 
281+ 
282+   @ doc  """ 
283+   Store raw settings on the Nerves Key 
284+ 
285+   This overwrites all of the settings and should be used with care since there's 
286+   no protection against race conditions with other users of this API. 
287+   """ 
288+   @ spec  put_raw_settings ( ATECC508A.Transport . t ( ) ,  binary ( ) )  ::  :ok 
289+   def  put_raw_settings ( transport ,  raw_settings )  when  is_binary ( raw_settings )  do 
290+     if  byte_size ( raw_settings )  >  @ settings_max_length  do 
291+       raise  "Settings are too large and won't fit in the NervesKey. The max raw size is #{  
292+               @ settings_max_length  
293+             }  ."
294+     end 
295+ 
296+     padded_settings  =  pad ( raw_settings ,  @ settings_max_length ) 
297+     slots  =  break_into_slots ( padded_settings ,  @ settings_slots ) 
298+ 
299+     Enum . each ( slots ,  fn  { slot ,  data }  ->  ATECC508A.DataZone . write ( transport ,  slot ,  data )  end ) 
300+   end 
301+ 
302+   defp  pad ( bin ,  len )  when  byte_size ( bin )  <  len  do 
303+     to_pad  =  8  *  ( len  -  byte_size ( bin ) ) 
304+     << bin :: binary ,  0 :: size ( to_pad ) >> 
305+   end 
306+ 
307+   defp  pad ( bin ,  _len ) ,  do:  bin 
308+ 
309+   defp  break_into_slots ( bin ,  slots )  do 
310+     break_into_slots ( bin ,  slots ,  [ ] ) 
311+     |>  Enum . reverse ( ) 
312+   end 
313+ 
314+   defp  break_into_slots ( << >> ,  [ ] ,  result ) ,  do:  result 
315+ 
316+   defp  break_into_slots ( bin ,  [ slot  |  rest ] ,  result )  do 
317+     slot_len  =  ATECC508A.DataZone . slot_size ( slot ) 
318+     { contents ,  next }  =  :erlang . split_binary ( bin ,  slot_len ) 
319+     break_into_slots ( next ,  rest ,  [ { slot ,  contents }  |  result ] ) 
320+   end 
321+ 
233322  # Configure an ATECC508A or ATECC608A as a NervesKey. 
234323  # 
235324  # This is called from `provision/4`. It can be called multiple 
0 commit comments