;;; -*- Lisp -*-
;;; $Id$

;;; Copyright (C) 2007--2008  American Registry for Internet Numbers ("ARIN")
;;;
;;; Permission to use, copy, modify, and distribute this software for any
;;; purpose with or without fee is hereby granted, provided that the above
;;; copyright notice and this permission notice appear in all copies.
;;;
;;; THE SOFTWARE IS PROVIDED "AS IS" AND ARIN DISCLAIMS ALL WARRANTIES WITH
;;; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
;;; AND FITNESS.  IN NO EVENT SHALL ARIN BE LIABLE FOR ANY SPECIAL, DIRECT,
;;; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
;;; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
;;; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
;;; PERFORMANCE OF THIS SOFTWARE.

;;; Scratch pad for working out API design for RPKI engine.
;;;
;;; This file is pseudocode, I just wanted to take advantage of
;;; emacs's built-in support for languages with reasonable syntax.
;;;
;;; Terminology:
;;;
;;; - IRBE: Internet Registry Back End
;;;
;;; - RE: RPKI Engine

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; Protocol operations between IRBE and RE.
;;;
;;; This is really two separate protocols over channels that might or
;;; not be the same.  Both are client/server protocols, but for some
;;; the RE is the client and for others the IRBE is the client.
;;;
;;; This set of operations are initiated by the IRBE.
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; This part of the protcol uses a kind of message-passing.  Each
;;; object that the RE knows about takes five messages: :create, :set,
;;; :get, :list, and :destroy.  Actions which are not just data
;;; operations on objects are handled via an SNMP-like mechanism, as
;;; if they were fields to be set.  For example, to generate a keypair
;;; one "sets" the :generate-keypair field of a biz-signing-context
;;; object, even though there is no such field in the object itself.
;;; This is a bit of a kludge, but the reason for doing it as if these
;;; were variables being set is to allow composite operations such as
;;; creating a biz-signing-context, populating all of its data fields,
;;; and generating a keypair, all as a single operation.  With this
;;; model, that's trivial, otherwise it's at least two round trips.
;;;
;;; Fields can be set in either :create or :set operations, the
;;; difference just being whether the object already exists.  A :get
;;; operation returns all visible fields of the object.  A :list
;;; operation returns a list containing what :get would have returned
;;; on each of those objects.
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; "Self" ID context -- one RE instance.  In degenerate case there
;; will be only one, but in hosting environments there might be many.
;;
;; We haven't yet defined any standard preferences, so none are shown.
;;
;; Extensions might also show up as preferences, using the
;; extension-preference syntax.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(self :action :create
      (:extension-preference "name" "Launcelot")
      (:extension-preference "quest" "Holy Grail"))
=> (self :self-id 42)

(self :action :set
      :self-id 42
      (:extension-preference "color" "Blue")
      ;;
      ;; <self> objects have a lot of actions:
      ;;
      (:rekey)				; Change all RPKI keys in this context now
      (:reissue)			; Reissue any cert with changed keys
      (:revoke)				; Revoke any old keys
      (:run-now)			; Run this self context now
      (:publish-world-now))		; Publish everything in this context now
=> (self :self-id 42)

(self :action :get
      :self-id 42)
=> (self
    :self-id 42
    (:extension-preference "name" "Launcelot")
    (:extension-preference "quest" "Holy Grail")
    (:extension-preference "color" "Blue"))

(self :action :list)
=> ((self
     :self-id 42
     (:extension-preference "name" "Launcelot")
     (:extension-preference "quest" "Holy Grail")
     (:extension-preference "color" "Blue"))
    (self
     :self-id 99
     (:extension-preference "name" "Arthur, King of the Britons")
     (:extension-preference "quest" "Holy Grail")
     (:extension-preference "airspeed-velocity-of-an-unladen-swallow"
			    "African or European swallow?")))

(self :action :destroy
      :self-id 42)
=> (self :self-id 42)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Business signing key context -- bundles all the stuff we need to
;; sign outgoing CMS messages with a business key.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(biz-signing-context :action :create
		     :self-id 42
		     (:signing-cert cert1)
		     ;;
		     ;; Actions:
		     ;;
		     (:generate-keypair :key-type :rsa
					:hash-alg :sha1
					:key-length 2048))
=> (biz-signing-context :biz-signing-context-id 17
			(:pkcs10-cert-request req))

(biz-signing-context :action :set
		     :self-id 42
		     :biz-signing-context-id 17
		     (:signing-cert cert2))
=> (biz-signing-context :biz-signing-context-id 17)

(biz-signing-context :action :get
		     :self-id 42
		     :biz-signing-context-id 17)
=> (biz-signing-context :biz-signing-context-id 17
			(:signing-cert cert1)
			(:signing-cert cert2)
			(:public-key key))

(biz-signing-context :action :list
		     :self-id 42)
=> ((biz-signing-context :biz-signing-context-id 17
			 (:signing-cert cert1)
			 (:signing-cert cert2)
			 (:public-key key)))

(biz-signing-context :action :destroy
		     :self-id 42
		     :biz-signing-context-id 17)
=> (biz-signing-context :biz-signing-context-id 17)


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Parent context -- represents one parent of this RE
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(parent :action :create
	:self-id 42
	(:ta ta)
	(:uri uri)
	(:sia-base sia-base)
	(:biz-signing-context biz-signing-context)
	(:repository repository))
=> (parent :parent-id 666)

(parent :action :set
	:self-id 42
	:parent-id 666
	(:ta ta)
	(:uri uri)
	(:sia-base sia-base)
	(:biz-signing-context biz-signing-context)
	(:repository repository)
	;;
	;; Actions:
	;;
	(:rekey)			; Change all keys now
	(:reissue)			; Reissue all certs with changed keys now
	(:revoke))			; Revoke any old keys now
=> (parent :parent-id 666)

(parent :action :get
	:self-id 42
	:parent-id 666)
=> (parent :parent-id 666
	   (:ta ta)
	   (:uri uri)
	   (:sia-base sia-base)
	   (:biz-signing-context biz-signing-context)
	   (:repository repository))

(parent :action :list
	:self-id 42
	:parent-id 666)
=> ((parent :parent-id 666
	    (:ta ta)
	    (:uri uri)
	    (:sia-base sia-base)
	    (:biz-signing-context biz-signing-context)
	    (:repository repository)))

(parent :action :destroy
	:self-id 42
	:parent-id 666)
=> (parent :parent-id 666)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Child context -- represents one child of this RE
;;
;; "child-db-id" may be unnecessary -- old API had both "child" and
;; "child-id", the second of which was a settable attribute of child,
;; I'm not quite sure what it was, so here I'm calling it child-db-id
;; in case we need it for something.  Perhaps this corresponds to the
;; optional child ID in the list-resources callback to the IRBE?
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(child :action :create
       :self-id 42
       (:ta ta)
       (:biz-signing-context biz-signing-context)
       (:child-db-id child-db-id))
=> (child :child-id 3)

(child :action :set
       :self-id 42
       :child-id 3
       (:ta ta)
       (:biz-signing-context biz-signing-context)
       (:child-db-id child-db-id)
       (:reissue))			; Reissue any certs to this child now
=> (child :child-id 3)

(child :action :get
       :self-id 42
       :child-id 3)
=> (child :child-id 3
	  (:ta ta)
	  (:biz-signing-context biz-signing-context)
	  (:child-db-id child-db-id))

(child :action :list
       :self-id 42
       :child-id 3)
=> ((child :child-id 3
	   (:ta ta)
	   (:biz-signing-context biz-signing-context)
	   (:child-db-id child-db-id)))

(child :action :destroy
       :self-id 42
       :child-id 3)
=> (child :child-id 3)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Repository context -- represents one repository in which this RE
;; publishes objects it signs.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(repository :action :create
	    :self-id 42
	    (:uri uri)
	    (:ta ta)
	    (:biz-signing-context biz-signing-context))
=> (repository :repository-id 120)

(repository :action :set
	    :self-id 42
	    :repository-id 120
	    (:uri uri)
	    (:ta ta)
	    (:biz-signing-context biz-signing-context))
=> (repository :repository-id 120)

(repository :action :get
	    :self-id 42
	    :repository-id 120)
=> (repository :repository-id 120
	       (:uri uri)
	       (:ta ta)
	       (:biz-signing-context biz-signing-context))

(repository :action :list
	    :self-id 42
	    :repository-id 120)
=> ((repository :repository-id 120
		(:uri uri)
		(:ta ta)
		(:biz-signing-context biz-signing-context)))

(repository :action :destroy
	    :self-id 42
	    :repository-id 120)
=> (repository :repository-id 120)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Route Origin objects (prototype and control for ROAs)
;;
;; Previous versions of this protocol handled this via queries from
;; the RE back into the IRBE, but the design group now believes that
;; an imperative interface makes more sense.  We stick to the same
;; general object model used above because ROAs are published objects,
;; thus the IRBE presumably wants some kind of handle on the ROA.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(route-origin :action :create
	      :self-id 42)
=> (route-origin :route-origin-id 88)

(route-origin :action :set
	      :self-id 42
	      :route-origin-id 88
	      :as-number 12345
	      :publish :yes
	      (:ipv4-prefix 10.0.0.44 32)
	      (:ipv4-range  10.2.0.6 10.2.0.77)
	      (:ipv6-prefix 2002:a00:: 48)
	      (:ipv6-range  2002:a02:6:: 2002:a02:4d::))
=> (route-origin :route-origin-id 88)

(route-origin :action :get
	      :self-id 42
	      :route-origin-id 88)
=> (route-origin :route-origin-id 88
		 (:as-number 12345)
		 (:ipv4-prefix 10.0.0.44 32)
		 (:ipv4-range  10.2.0.6 10.2.0.77)
		 (:ipv6-prefix 2002:a00:: 48)
		 (:ipv6-range  2002:a02:6:: 2002:a02:4d::))

(route-origin :action :list
	      :self-id 42)
=> ((route-origin :route-origin-id 88
		  (:as-number 12345)
		  (:ipv4-prefix 10.0.0.44 32)
		  (:ipv4-range  10.2.0.6 10.2.0.77)
		  (:ipv6-prefix 2002:a00:: 48)
		  (:ipv6-range  2002:a02:6:: 2002:a02:4d::)))

(route-origin :action :destroy
	      :self-id 42
	      :route-origin-id 88)
=> (route-origin :route-origin-id 88)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; "Blind object signing" would probably be another imperative message
;; to be added above, similar to (route-origin).
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; Protocol operations between IRBE and RE.
;;;
;;; This is really two separate protocols over channels that might or
;;; not be the same.  Both are client/server protocols, but for some
;;; the rpki engine and for others the irbe is the client.
;;;
;;; This set of operations are initiated by the RE.
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(list-resources :self-id 42		; issuer id
		:child id)		; subject id
=> (resources :valid-until 2008-04-01T00:00:00Z
    ((:ipv4-prefix 10.0.0.44 32)
     (:ipv4-prefix 10.3.0.44 32)
     (:ipv6-prefix fe80:dead:beef:: 48)
     (:as-number 666))
    ((:subject-name "wombats are us")	; Allowed in protocol, but RE may reject with error
     (:ipv4-prefix 10.2..0.6 32)
     (:ipv6-prefix fe80:dead:beef:: 48)
     (:ipv6-range fe80:dead:beef:: fe80:dead:beef::49)
     (:as-number 666))
    ...)

(report-error :self-id 42
	      :error-token :your-hair-is-on-fire
	      :bag-of-data whatever)
=> ()